Friday 27 December 2013

"xargs" All-IN-One Tutorial Guide

xargs:


xargs is a just like "awk" ,"find" & "grep" commands processes the standard input on all unix flavoured operating sysems.

Basically "xargs" is used to remove or do some operation on long list of file names which were produced by "find" & "grep" commands.

Usually many UNIX operating system doesn't accept such a long list of argument.UNIX xargs command divide that list into sub-list with acceptable length and made it work.

For example I'd like to find out all *.sh file located in 100s of sub-directories and move them to another directory called ~/back.scripts. How do I use command line args with xargs to achieve the same?

as per man page "xargs" is used to execute a command, passing constructed argument list(s). The arguments are typically a long list of filenames (generated by ls or find etc) that are passed to xargs via a pipe.

Some features:

  • xargs can execute the command supplying some initial arguments directly, and reading the remaining arguments from standard input (or piped input).
  • xargs passes arguments to command in several bundles, this allows command to process more arguments than it could normally handle at once.
  • Arguments in the standard input must be separated by unquoted blank characters, or unescaped blank characters or newline characters.
  • Characters can be quoted by enclosing them in "double-quotes" (non-double-quote and non-newline chars only).
  • Characters can be quoted by enclosing them in 'apostrophes' (non-apostrophe and non-newline chars only).
  • Any unquoted character can be escaped by preceding it with a backslash.

e.g. file1 file2 "file three" 'file four' file\ five
If command is omitted then the equivalent of /bin/echo is used.

 Exit Status

This command returns the following exit values:
Item Description
0 All invocations of the Command parameter returned exit status 0.
1-125 A command line meeting the specified requirements could not be assembled, one or more of the invocations of the Command parameter returned a non-zero exit status, or some other error occurred.
126 Command was found but could not be invoked.
127 Command could not be found.

Examples

Find all the .mp3 files in the music folder and pass to the ls command, -print0 is required if any filenames contain whitespace.:
   find ./music -name "*.mp3" -print0 | xargs -0 ls

Find all files in the work folder, pass to grep and search for profit:
   find ./work -print | xargs grep "profit"

{} as the argument list marker

{} is the default argument list marker. You need to use {} this with various command which take more than two arguments at a time. For example mv command need to know the file name. The following will find all .bak files in or below the current directory and move them to ~/.old.files directory:

$ find . -name "*.sh" -print0 | xargs -0 -I {} mv {} ~/back.scripts

You can rename {} to something else. In the following example {} is renamed as file. This is more readable as compare to previous example:
$ find . -name "*.sh" -print0 | xargs -0 -I file mv file ~/back.scripts

Where,
    -0 If there are blank spaces or characters (including newlines) many commands will not work. This option take cares of file names with blank space.
    -I Replace occurrences of replace-str in the initial-arguments with names read from standard input. Also, unquoted blanks do not terminate input items; instead the separator is the newline character.

10 Popular  "XARGS" Command Examples:

1) With& Without "xargs" observation:

 in this example of xargs command we will see how output changes with use of xargs command in unix or Linux. Here is the output of find command without xargs first and than with xargs, you can clearly see that multiline output is converted into single line:
um@server#find . -name "*sh*"
./.bash_history
./.bash_profile
./.bash_profile.cf-before-edit
./.cshrc
./.cshrc.cf-before-edit
./.sh_history
./.ssh
./.ssh2
./scripts/aix_sysinfo.ksh
./scripts/chperm_messages.sh
./scripts/linux_sysinfo.ksh
./scripts/solaris_sysinfo_v1.1.ksh
./testlocked.ksh

um@server# find . -name "*bash*" | xargs
./.bash_history ./.bash_profile ./.bash_profile.cf-before-edit ./.cshrc ./.cshrc.cf-before-edit ./.sh_history ./.ssh ./.ssh2 ./scripts/aix_sysinfo.ksh ./scripts/chperm_messages.sh ./scripts/linux_sysinfo.ksh ./scripts/solaris_sysinfo_v1.1.ksh ./testlocked.ksh

2) Xargs with grep:

When you use "xargs" in conjusction with find and grep , the grep will look for the specifig word in  each file in the from the stanadard input.
#find . -name "*.sh" | xargs grep "ksh"

In the above exanmple first find all .sh  files from current directory or below and than on each .sh file look for word "ksh".

3) Covert muti line output into single line

best example of xargs is  converting output of one command into one line. For example you can run any command and then combine xargs to convert output into single line. here is an example xargs in unix which does that.
um@server#ls -1 *.sh
linux_sysinfo.sh
aix_sysinfo.sh
audit_script.sh
chperm_messages.sh

um@system#ls -1 *.sh | xargs
linux_sysinfo.sh aix_sysinfo.sh audit_script.sh chperm_messages.sh

4) To Delete temporary files using xargs & find:

Another common example of xargs command in unix is removing temporary files from system.
#find /tmp -name "*.tmp" | xargs rm

This will remove all .tmp file from /tmp or below directory. xargs in unix is very fast as compared to deleting single file at a time which can also be done by using find command alone

5)  xargs -0 to handle space in file name

Above example of xargs command in unix will not work as expected if any of file name contains space or new line on it. To avoid this problem we use find -print0 to produce null separated file name and xargs-0 to handle null separated items. Here is an example of xargs command in unix which can handle file name with spaces and newline:
#find /tmp -name "*.tmp" -print0 | xargs -0 rm

6) Counting number of lines/words/characters in each file using xargs & find:

"find"in conjuction with "xargs" and "wc"  we can count number of lines/words/characters in each file under a perticaular directory.
um@server#ls -1 *.sh | xargs wc -l
112 linux_sysinfo.sh
85  aix_sysinfo.sh
35  audit_script.sh
18  chperm_messages.sh
250 total

Note: you can use '-c' & '-w' with wc to obtain number of characters and words repectively.

7) xargs and cut command in Unix:

 Though most of xargs examples in unix will be along with find and grep command but xargs is not just limited to this two it can also be used with any command which generated long list of input for example we can use xargs with cut command in unix. In below example of unix xargs we will xargs example with cut command. for using cut command let's first create a .csv file with some data e.g.

um@server# cat fruits.txt
Orange,Greenorange
Mango,Redmango
Banana,Pinkbanana

Now we will display name of actual fruit from first column using xargs command in one line:

um@server:/etc cut -d, -f1 fruits.txt | sort | xargs
Orange Mango Banana

8)To insert file names into the middle of command lines, type:

um@server#ls | xargs  -t  -I  {} mv {} {}.old

This command sequence renames all files in the current directory by adding .old to the end of each name. The -I flag tells the xargs command to insert each line of the ls directory listing where {} (braces) appear. If the current directory contains the files chap1, chap2, and chap3, this constructs the following commands:

#mv chap1 chap1.old
#mv chap2 chap2.old
#mv chap3 chap3.old

9) To run a command on files that you select individually, type:

um@server# ls | xargs  -p  -n  1 ar r lib.a

This command sequence allows you to select files to add to the lib.a library. The -p flag tells the xargs command to display each ar command it constructs and to ask if you want to run it. Type y to run the command. Press the any other key if you do not want to run the command.

Something similar to the following displays:

ar r lib.a chap1 ?...
ar r lib.a chap2 ?...
ar r lib.a chap3 ?...

10) To construct a command that contains a specific number of arguments and to insert those arguments into the middle of a command line, type:

um@server# ls | xargs -n6 | xargs -I{} echo {} - some files in the directory

If the current directory contains files chap1 through chap10, the output constructed will be the following:
chap1 chap2 chap3 chap4 chap5 chap6 - some files in the directory
chap7 chap8 chap9 chap10 - some file in the directory

8 comments:

  1. Thanks for the very useful examples! Now I have the challenge that I need to sort the results of find before processing them with xargs while the file names may contain blanks. When using the -print0 option of find and the -0 option of xargs, on Linux I could use "find .... -print0 | sort -z | xargs -0 ....". Unfortunately on Solaris sort uses -z for different purposes and I can't find any other option allowing null-terminated input. Any suggestions? Thanks in advance - Ralph

    ReplyDelete
  2. Great tutorial! Thanks.

    ReplyDelete
  3. Nice..No7 - dont understand smartphone.csv in the command example.Should be fruits.txt obviuously.Can be confusing for someone..

    ReplyDelete
    Replies
    1. Corrected it , thanks for bringing to our notice.

      Delete
  4. using xargs for finding and removing files is strongly bad example, because teach bad practices.
    find can call rm command by -exec , then xargs is unneded. otherways, find has -delete facility, and can remove file without calling any external command.
    But in examples above is misset important information, xargs can do its work in parallel. For example, we can call gzip *.log , then files will be compressed one by one. but we can do the same, using all CPU resources, calling find -type f -name '*.log'|xargs -n1 -P3 -r gzip , then will be call 3 gzip processes in parallel. Option -r is strongly needed, because in default xargs call command without input argument one, if input (stdin) stream is empty. -r option will prevent this.
    But.... did you consider using parallel command? It is one of GNU official tool :)

    ReplyDelete