咱们能够用管道将一个命令的stdout(标准输出)重定向到另外一个命令的stdin(标准输入),如:bash
$ cat foo.txt | grep "test"
解析:查看foo.txt文件并打印出含有test的行。命令行
可是有些命令只能以命令行参数的形式接受数据,而没法经过stdin接受数据流。在这种状况下,咱们无法用管道来提供哪些只有经过命令行参数才能提供的数据。code
那如今就该xargs上场了,它擅长将标准输入数据转换成命令行参数。字符串
预备知识:源码
xargs命令应该紧跟在管道操做符以后,以标准输入做为主要的源数据流,它使用stdin并经过提供命令行参数来执行其余命令。xargs命令把从stdin接收到的数据从新格式化,再将其做为参数提供给其余命令。it
1、将多行输入转换成单行输出test
$ cat foo.txt # 样例文件 1 2 3 3 4 5 7 8 9 10 11 12 $ cat foo.txt | xargs 1 2 3 4 5 6 7 8 9 10 11 12
2、 将单行输入转换为多行输出扩展
$ cat foo.txt | xargs -n 3 1 2 3 4 5 6 7 8 9 10 11 12
解析:指定每行最大的参数数量n,将任何来自stdin的文本划分红多行,每行n个参数。file
xargs默认的定界符是空格,咱们本身能够来设置定界符,用-d选项为输入指定一个定制的定界符。循环
$ echo "splitXsplitXsplitXsplit" | xargs -d X split split split split
结合-n选项,咱们能够将输入划分红多行,每行包含两个参数。
$ echo "splitXsplitXsplitXsplit" | xargs -d X -n 2 split split split split
3、如何将参数传递给命令 读取stdin(标准输入),将格式化参数传递给命令
编写一个小型的echo来更好的理解用xargs提供命令行参数的方法:
#!/bin/bash #filename: cecho.sh echo $@ "#"
当参数传递给cecho.sh后,它将会把这些参数打印出来,并以# 字符结尾
$ ./eceho.sh arg1 arg2 arg1 arg2 #
那么,咱们如今想把这个命令执行屡次, 每次使用一个参数,难道咱们只能一遍一遍的执行?如今,咱们有一个名为args.txt的参数列表文件,内容为:
arg1 arg2 arg3
咱们来看下面的代码
$ cat args.txt | xargs -n 1 ./cecho.sh arg1 # arg2 # arg3 #
每次执行须要X个参数的命令时,使用:
$ cat args.txt | xargs -n 2 ./cecho.sh arg1 arg2 # arg3 #
可是有些时候,咱们须要一些不变的参数,看下面这种命令格式:
$ ./cecho -p arg1 -1
在上面的命令执行过程当中,arg1 是惟一可变的参数,其他部分都保持不变,咱们能够从文件(argx.txt)中读取参数,按照下面的方式提供给命令:
./cecho -p arg1 -1 ./cecho -p arg2 -1 ./cecho -p arg3 -1
xargs有个一个-I(大写的i)的选项,能够提供上面这种形式的命令执行序列。咱们用-I指定替换字符串,这个字符串在xargs扩展(传递给命令)时会被替换掉。若是将-I与xargs结合使用,对于每个参数,命令都会被执行一次。
$ cat args.txt | xargs -I {} ./cecho -p {} -1 -p arg1 -1 # -p arg2 -1 # -p arg3 -1 #
-I {}指定了替换字符串。对于每个命令参数,字符串{}都会被从stdin读取到的参数所替换掉。使用-I的时候,命令会以循环的方式执行。若是有3个参数,那个命令就会被执行3次。在每一次执行的时候{}都会被替换为相应的参数。
xargs常常会与find一块儿使用,不过人们一般都会以一种错误的方式去使用它们。
$ find . type -f -name "*.txt" -print | xargs rm -f {} \;
咱们无法预测find命令输出的结果的定界符是什么('\n'或' ')。不少文件都有可能包含空格符(' '),所以xargs极可能会误认为它们是定界符(例如:hell text.txt会被xargs理解为hello和text.txt两个文件)。
只要咱们把find的输出做为xargs的输入,就必须将-print0与find结合使用,以字符null('\0')来分隔输出。
用find匹配并列出全部的.txt文件,而后用xargs将这些文件删除:
$ find . -type f -name "*.txt" -print0 | xargs -0 rm -f {} \;
这样就能够删除全部的.txt文件,xargs -0将\0做为输入的定界符。
统计源码目录下全部.sh的文件行数。
$ find . type f -name "*.sh" -print0 | xargs -0 wc -l