Linux xargs命令

xargs 可以将内容按照空白符分隔开,然后将分割后的内容作为参数传递给其他命令。默认情况下,xargs 会将这些参数传递给 echo 命令。

比如直接执行 xargs 命令时,会等待用户输入,直到用户输入 ctrl+d,才会结束

$ xargs
abc
def
hik       <--- 此处输入完成后回车,ctrl+d
abc def hik    <-----显示的结果,将你输入的内容按照空白字符分割(空格,回车换行等),打印出来

-t 显示执行的命令

$ xargs -t     # -t 参数:显示执行的命令
abc
123            # 输入了 abc 和 123, ctrl+d 结束输入
echo abc 123   # 实际执行的命令是 echo, 并且拿到了 xargs 传递过来的所有参数
abc 123

-d 分隔符:分隔符

xargs默认用空格、换行符、制表符等作为分割,把标准输入分割成一个个命令参数

$ echo 'a b      c' | xargs
a b c          <-- 把上面空格分割,然后打印出来各个参数

自定义分隔:

$ echo 'a b      c' | xargs -d 'b'      <-- 用字符‘b’分割
a        c

-p:用户确认

-p参数可以在执行命令时,弹出确认消息,让用户确认后才会执行相应的命令

$ echo 'a b      c' | xargs -d 'b' -p
echo a        c
 ?...y               <-- 输入y,确认
a        c

-n 数量:指定将几个参数传递给命令

忽略 -n 参数则默认一次性将所有参数传递给后面的命令。

$ echo 'a      b c' | xargs -t echo
echo a b c       # 执行的是 echo a b c,也就是把所有的参数一次性传递给了echo
a b c

-n 1 将每次传递一个参数,也就是将a b c这三个参数,一个一个的交给echo执行

$ echo 'a      b c' | xargs -n 1 -t echo   # 设定每次传递1个参数给echo
echo a          # 看的出来,就传递了一个a
a
echo b
b
echo c
c

-i str:给参数的值起个变量名 strstr 可以忽略,默认的变量名是 {}。官方建议使用大写的 -I 来指定参数。

先ls一下,查看文件

$ ls
aaa  chrome.lnk*  eclipse.lnk*  help.txt  name.txt  Typora.lnk*
$ ls | xargs -i echo "{} .." # -i 指定参数,没写参数名,则默认使用 {}
aaa ..
chrome.lnk* ..
eclipse.lnk* ..
help.txt ..
name.txt ..
Typora.lnk* ..

-I str:类似 -i

$ ls | xargs -I 'name' echo "name ...."  # 将传递的参数命名为 name
aaa ....
chrome.lnk* ....
eclipse.lnk* ....
help.txt ....
name.txt ....
Typora.lnk* ....

-0:以 null 作为分隔符

默认情况下 xargs 使用空白符来分割内容,如果搭配 find 命令来使用,并且 find 查找出来的文件名包含空格,那么就会出现问题。

因此,find 命令有个参数 -print0,可以将查找的内容以 null 分割(即查找出的所有内容不换行显示)。xargs 的 -0 参数就代表按照 null 来分割参数,可以配合 find 使用。

比如正常的 find

$ find -type f
./a b c   e.pub      # 注意这个名字带有空格的文件
./aaa
./chrome.lnk
./eclipse.lnk
./help.txt
./name.txt
./Typora.lnk

find 命令的 -print0 参数

$ find -type f -print0
./a b c   e.pub./aaa./chrome.lnk./eclipse.lnk./help.txt./name.txt./Typora.lnk  # 以null分割,每个文件之间没有换行输出

配合 xargs 使用(但是不使用 -0 参数),名字带有空格的文件被拆分了!

$ find -type f | xargs -n 1
./a     # 文件名有空格,因此这个文件名被拆开了!
b
c
e.pub
./aaa
./chrome.lnk
./eclipse.lnk
./help.txt
./name.txt
./Typora.lnk

使用 find 的 -print0 和 xargs 的 -0

$ find -type f -print0 | xargs -n 1 -0
./a b c   e.pub              # 文件完好
./aaa
./chrome.lnk
./eclipse.lnk
./help.txt
./name.txt
./Typora.lnk

其实上面这个例子不使用 -0 也可以,比如手动指定分隔符为 \n,即回车换行符,而不用默认的空白符号:

$ find -type f| xargs -d '\n' -n 1
./a b c   e.pub
./aaa
./chrome.lnk
./eclipse.lnk
./help.txt
./name.txt
./Typora.lnk

-L 数量:用几行作为命令参数

-L可以将每行的数据进行分割,然后再把几行的数据重组,作为一个整体传递给下一个命令

下面的例子有三行数据,注意中间的\n,前两行数据又有很多空格,xargs 将这些行进行分割,然后每几行的参数放到一起,传递给下一个命令(默认是echo,显示消息)

$ printf "a    b c\nd e     f\nghi" | xargs -L 1
a b c           # a b c,一次传递一行参数给echo
d e f
ghi
$ printf "a    b c\nd e     f\nghi" | xargs -L 2 
a b c d e f     # 一次性传递了两行
ghi

-P 数量:一次用几个进程执行

-P 0 代表不限制几个进程,-P 2代表用2个进程。

示例

查询当前目录下的、文件内容包含 ‘while’ 的文件。

$ find . -maxdepth 1 -type f -print0 | xargs -0 -n 1 grep -n -H "while"
./a.py:29:while True:
./b.py:28:while True:

这里的 xargs 和 grep 命令之间不需要使用管道符。原因是:

  • xargs 本来就是用来联合其他命令使用的,它可以将标准输入的内容分割成参数,传递给后续的命令。

  • grep 可以接收标准输入和文件中搜索内容,当接收标准输入时,grep 会在标准输入中搜索。如果 grep 接收的是文件名,那么它会在这些文件的内容中搜索

在上面的例子中,如果我们不使用 xargs,并直接将 find 命令的输出通过管道传递给 grep,那么 grep 查询的是文件路径包含 while 的文件路径:

$ find . -maxdepth 1 -type f | grep -n -H "while"
(standard input):98:./while_do_it.mp4
(standard input):111:./sorry late for a while.mp4

因此为了查询文件的内容包含 while,需要将这些文件名传递给 grep 命令,从而让 grep 去文件的内容中搜索 while,因此我们需要将 find 命令找的文件路径通过管道传递给 xargs 命令,xargs 命令将这些文件路径字符串分割成单独的文件路径(而非作为一整个字符串),然后再将这些文件路径传递给 grep 命令(并且 xargs 命令和 grep 命令之间不使用管道,一旦使用管道,又变成了 grep 在文件名中搜索了)

posted @ 2020-07-29 16:31  wztshine  阅读(250)  评论(0)    收藏  举报