Linux那点事-xargs命令详解
1. 为什么需要xargs命令
1.1 管道|的缺陷
管道实现的是将前面的输出stdout作为后面的输入stdin,但是有些命令不接受管道的传递方式。例如:ls,这是为什么呢?
因为有些命令希望管道传递过来的是参数,但是直接使用管道有时无法传递到命令的参数位。这时候就需要xargs,xargs实现的是将管道传递过来的stdin进行处理然后传递到命令的参数位置上。
用户查找文件:
用户希望处理查找后的文件:
管道的缺陷也就是xargs完成了两个行为:
1. 处理管道传输过来的
stdin;
2. 将处理后的数据传递到正确的位置;
1.2 xargs对数据的处理
处理大量数据的时候,可能会发生参数列表过长的情况。而xargs将完成参数的定位我们清楚,但是
xrags如何处理管道传输的stdin呢?
其实就是完成两个操作:
1. 对数据的分割;
2. 对数据的分批;
xargs处理的优先级或顺序:先分割,在分批,然后传递到参数位。
可以设想一个场景,我想对一堆数据进行处理,实际上是对一堆中的每个数据进行分别的处理。那么如何将一堆数据按照自定义规则分割为独立的数据?若是一次性传递的数据过多,又该如何处理?
1.2.1 xrags的并发处理
但需要注意的是,尽管实现了分批处理,但是默认情况下并没有提高任何效率,因为分批传递之后还是一次执行一个。而且有时候分批之后是将其作为一个参数的整体,并不会将分批中的信息分段执行。
但事实上,xargs提供了-P选项,用于指定并发执行的数量(默认是只要一个处理进程,不会提供效率,但是可以指定为N个子进程,或者指定为0表示尽可能多的利用CPU)。这样就能将让分批操作更好的利用多核CPU,从而提升效率。例如上面分成了两批,指定-P 2可以并发执行两批,而并非执行完第一批之后再执行第二批。
剩下的功能就是处理xargs的细节问题了,比如如何分割(xargs、xargs -d、xargs -0),分割后如何划批(xargs -n、xargs -L),参数如何传递(xargs -i)。另外xargs还提供了询问交互处理(-p选项)和预先打印一遍命令执行情况(-t选项),传递终止符(-E选项)等。
1.2.2 执行命令准备
命令准备:
start 1 2 3 end
start 4 5 6 end
start 7 8 9 end
start 10 end
由于指定了参数传递位置,所以必须使用-i,那就无法一次传递3个数,要解决这个问题,就要想办法让每三个树分一次段,然后后使用-i传递,那么可以将每三个数分一次行写入一个文件。
例如:
当然,也可以多次使用xargs。在很多使用无法解决分段的问题都可以通过多次使用xargs来解决。
5. 分批选项的生效规则
-i、-L、-n选项都是分批选项,他们的生效规则是:谁指定在后面,谁就生效!!!
实际上,-i就是隐含了-L 1,-i是分批并传递这两个作用跟严格些。
6. xargs观察命令的执行过程
使用-p选项是交互询问式的,只有每次询问的时候输入y(或者yes)才会执行,直接按entry键是不会执行的。
使用-t选项是在每次执行xargs后面的命令都会先在stderr上打印一遍命令的执行过程然后才正式执行。
使用-p和-t选项就可以根据xargs后面的命令的执行顺序进行推测,xargs是如何分段,分批以及传递的。
【后续】 分批选项的的典型应用
1. 同一目录下文件过多
分批选项有时特别有用,例如脚本规定每次只能传递三个参数,有时候grep或者rm -rf文件数量特别多的时候会提示参数列表过长而导致失败,这时候就可以分批来按批查询或删除。
命令:ls | xargs -n 10000 rm -rf
2. xargs+find的使用
xargs原本就是为find而开发的。
find命令将匹配到的文件传递给xargs命令,而xargs命令每次只获取一部分而不是全部。不像-exec选项那样,这样就可以先处理最先获取的一部分文件,然后是下一批。
实际应用:
ls+grep跨目录查询时,我们将文件通过管道输入到grep参数处,此时并没有包含目录地址,边会出现下面的错误。
解决方案:
将find找到的文件地址传递给grep命令的参数处。