xargs

xargs有什么用?

在linux中,有pipeline的概念,上一个命令执行完后,可以接着下一个命令执行。

比如我上一个命令是ls

# ls
cert  channel  msp  msp.bak  orderer  root-org1.crt

可以通过pipeline管道,接下一个grep命令

# ls|grep order
orderer

pipeline把上一个命令的标准输出stdout, 重定向到下一个命令的标准输入std,实现数据的传递。

有的linux命令是可以直接从stdin读取参数的,比如grep。但是有的命令是不可以的,比如ls, rm ,echo等

# ls|echo

执行上述命令,我们会发现什么都没有

为了解决这个问题,让这些命令都能从stdin标准输入读取参数,就是xargs的使命:

# ls|xargs echo
cert channel msp msp.bak orderer root-org1.crt

xargs把读取的参数用空格分隔,传递给后续命令。但注意的是,虽然它把参数按空格分离了出来,xargs不是传递一个参数,执行一次命令,而是把这些参数一次性的全部传递给后续命令

比如下面,xargs把空格分割的一整行参数全部传递给了第二个echo

$ echo {0..9}|xargs echo
0 1 2 3 4 5 6 7 8 9

我们希望控制xargs传递参数的个数,比如我们想两个参数一组,传递给echo。就需要-n参数。-n指定传递给xargs后续命令的最多参数个数

# echo {0..9}|xargs -n2 echo
0 1
2 3
4 5
6 7
8 9


其他常见用法

想把所有.jpg文件删除,当然你可以rm *.jpg,但是如果要递归操作所有子目录下的文件呢?

可以这样:

find . -name "*.jpg" | xargs rm


这样,所有被find找到的文件名,都会作为参数来调用rm命令了。

对于大多数情况,这一行命令没有问题,但是如有些文件名中包含空格,就会有问题了。xargs默认以空白符分隔接受到的输入,所以一个含有空格的文件名会被当做多个参数,分别传给rm。所以在处理文件名这类命令时,通常要这样:

find . -name "*.jpg" -print0 | xargs -0 rm

这里的-print0是告诉find命令,在每个输出后面以’\0’作为结束。-0是告诉xargs,使用’\0’来分隔输入,而不是空白符。这样就避免出现问题了。

下面再考虑另一种情况,假设不是删除,而是想把符合要求的文件名都添加上后缀.bak怎么办?这时候需要这样:

find . -name "*.jpg" -print0 | xargs -0 -I {} mv {} {}.bak


其中的-I {}是告诉xargs,后面的命令中,用{}表示占位符,将会被实际的参数替代。这样就行了。

其他有用的参数还有:
* -d 用于指定切分输入内容时,具体的分隔符
其他更多的参数,就参考man xargs吧。


Ref:

  • https://blog.csdn.net/yhcharles/article/details/44875865



发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

About Me

一位程序员,会弹吉他,喜欢读诗。
有一颗感恩的心,一位美丽的妻子,两个可爱的女儿
mail: geraldlee0825@gmail.com
github: https://github.com/lisuxiaoqi
medium: https://medium.com/@geraldlee0825