xargs是一个过滤器,可以给命令传递参数;也是组合多个命令的一个工具,它把一个数据流分割为一些足够小的块,以方便过滤器和命令进行处理。


通常情况下,xargs从管道或者stdin中读取数据,然而它也能够从文件的输出中读取数据。


xargs的默认命令是echo,这意味着通过管道传递给xargs的输入将会包含换行和空白,不过通过xargs的处理,换行和空白将被空格取代。


xargs是一个强有力的命令,它能够捕获一个命令的输出,然后传递给另外一个命令,下面是一些如何有效使用xargs 的实用例子。


EXAMPLES

find /tmp -name core -type f -print | xargs /bin/rm -f

Find files named core in or below the directory /tmp and delete them.  Note that this will work incorrectly if there are any filenames containing newlines or spaces.


find /tmp -name core -type f -print0 | xargs -0 /bin/rm -f

Find  files  named core in or below the directory /tmp and delete them, processing filenames in such a way that file or directory names containing spaces or newlines are correctly handled.


find /tmp -depth -name core -type f -delete

Find files named core in or below the directory /tmp and delete them, but more efficiently than in the previous example (because we avoid the need to use fork(2) and exec(2) to launch rm and we don't need the extra xargs process).


cut -d: -f1 < /etc/passwd | sort | xargs echo

Generates a compact listing of all the users on the system.


xargs sh -c 'emacs "$@" < /dev/tty' emacs

Launches the minimum number of copies of Emacs needed, one after the other, to edit the files listed on xargs' standard input.  This example achieves the same effect as BSD's -o option, but in a more flexible and portable way.


find /etc -name "*.conf" | xargs ls –l

Find all files ending with *.conf in or below the directory /etc. 


cat url-list.txt | xargs wget –c

If you have a file that contains a lot of URLs what you want to download, you can download all links using xargs


find / -name *.jpg -type f -print | xargs tar -cvzf p_w_picpaths.tar.gz

Find all of the JPG files, and compress it 


ls *.sh | xargs -n1 -i cp {} /external-hard-drive/directory

Copy all the shell files to an external hard drive


find . -name "*.log" -print0 | xargs -0 sed -i 's/aaa/bbb/g'

Find all files ending with *.log and to find the documents inside the contents of all the AAA characters are replaced by BBB


find -name "*.log" -mtime +10 -print0 |xargs -0 rm -rfv

以可视化的方式删除以log结尾的10天前的文件,包括带空格的文件:


find . -name '*.txt' -type f -print0 |xargs -0 grep -n 'aaa' 

将*.txt 的文件中包含aaa的行显示出来,并在前面列出行号,如果有多个文件,也会在前面有所显示。

[root@nagiostest tmp]# find . -name '*.txt' -type f -print0 |xargs -0 grep -n 'aaa' 

./2.txt:1:aadddaaaaaddddddddaaaaaaa 

./1.txt:1:aaaaaaaddddddddaaaaaaa



find中的-print0和xargs中-0的内涵

默认情况下, find 每输出一个文件名, 后面都会接着输出一个换行符 ('\n'), 因此我们看到的 find 的输出都是一行一行的:

[root@nagiostest tmp]# ll

total 0

-rw-r--r-- 1 root root 0 Jul 31 13:28 1.log

-rw-r--r-- 1 root root 0 Jul 31 13:28 2.log

-rw-r--r-- 1 root root 0 Jul 31 13:28 3.log

把所有的 .log 文件删掉, 可以配合 xargs 一起用:

find -name '*.log' | xargs rm


[root@nagiostest tmp]# ls -l

total 0

-rw-r--r-- 1 root root 0 Jul 31 15:53 a 1.log

-rw-r--r-- 1 root root 0 Jul 31 15:53 a 2.log

-rw-r--r-- 1 root root 0 Jul 31 15:53 a 3.log


[root@nagiostest tmp]# find -name '*.log' | xargs rm

rm: cannot remove `./a': No such file or directory

rm: cannot remove `1.log': No such file or directory

rm: cannot remove `./a': No such file or directory

rm: cannot remove `2.log': No such file or directory

rm: cannot remove `./a': No such file or directory

rm: cannot remove `3.log': No such file or directory

原因其实很简单, xargs 默认是以空白字符 (空格, TAB, 换行符) 来分割记录的, 因此文件名 ./a 1.log 被解释成了两个记录 ./a 和 1.log, 不幸的是 rm 找不到这两个文件.

解决此类问题的方法:

find 在打印出一个文件名之后接着输出一个 NULL 字符 ('\0') 而不是换行符, 然后再告诉 xargs 也用 NULL 字符来作为记录的分隔符. 

这就是 find 的 -print0 和 xargs 的 -0 的内涵。

一般的编程语言中都用 '\0' 来作为字符串的结束标志, 文件的路径名中不可能包含 '\0' 字符.选 '\0' 而不是其他字符做分隔符大概也是因此而来。