Xargs 基本用法

0X00 简单用法

内容比较少,主要是介绍一下 xargs ,直接开始吧~

首先假定各位能够熟练运用基础的管道操作,能够理解 ps aux | grep nginx | awk -F ' ' {print $1} 这样的命令。

我们日常使用管道的时候肯定会用到 ls | grep xxx | grep xxx | rm 这样的操作,想从一堆文件里筛选出自己需要的文件并将其删除/移动/复制等。但其实这样的操作是不行的,因为前面管道传过来的是数据流但是 rm 命令却并不能处理它。如果想实现这种效果就可以用 xargs 将其进行转换了,如下图所示使用 ls | grep bbb | grep "[3-5]" | xargs rm 就可以完成任务。

20221227-xargs-1

此处 xargs 的功能就是将前面的数据流逐行分解并一个个丢给 rm 去执行。不过通常的管道都是一个命令执行一次,配合 xargs 之后就是做一个循环了,将管道前面的的输出逐行取出作为参数交给下一个命令去执行。我这里画了一个简易的图,也许能够便于理解。

20221227-xargs-2

其实如果只是找到文件并删除的话,还有更简单的方法啦,例如 find . -regex "\./test_bbb_[3-5]" -delete

现在虽然解决了删除的问题,但其实并没有解决复制的问题。因为你写了 ls | xargs cp target_dir/. 之后它会翻译成 cp target_dir/. ./aaa ./bbb ./ccc 这样的命令,显然是不对劲的。所以 xargs 还提供了宏功能,使用类似 find . -regex "\./test_bbb_[3-5]" | xargs -I {} cp {} target_dir/. 这样的命令就可以将前面的输出拆分后准确的塞入到后面命令的指定位置,实现想要的功能了。

20221227-xargs-3

0X01 参数们

首先是关于「到底执行了什么」的参数,有两个分别是 -p-t,前者用于把即将执行的命令打印出来并询问是否执行(交互式),后者则是单纯的打出执行的命令。用法就是 ls | xargs -p rmls | xargs -t rm 这样简单。

其次就是上面介绍到的 -I 参数,宏命令,正如上面所说的那样,是设计一个模板并将其替换。⚠️需要注意的一个点是,{} 这个符号并非语法,而是你想用什么就用什么,比如 ls | xargs -I HONG_MING_LING cp HONG_MING_LING xxx/. 也是可以的,只是 {} 比较少出现在命令里并且也比较易于理解而已。

另外两个参数是 -L-n,前者表示「每多少行作为一组参数」,后者表示「每多少列作为一组参数」。下图所示,第一段是将每三行作为一组参数,所以可以看到执行的是 sleep 1 2 3sleep 4 5 这两个命令;第二段是将每行列作为一组参数,所以看到执行也是分了五步;最后一段是将每行的两列作为一组参数,所以执行的是 sleep 1 2sleep 3 4sleep 5

20221227-xargs-4
还有最后一个重要的参数是 -P,这个参数是用来控制并发的。前面介绍了 xargs 会将参数丢给后面的命令,逐个执行一遍。那么来看一下这个命令 find . -name "*.png" | xargs ./compression_png.py,是要将目录下所有的 png 文件压缩一遍没错了。但是如果这个脚本是单线程运行的话(大多数情况下 Python 脚本并不会真的并行执行)你的多核 CPU 就没有用武之地了,只会在压缩每个文件的时候抽取一个幸运核心来工作,其他核心就休息。想要并行的话改脚本当然是麻烦了,可以给 xargs 加上一个 -P 参数就实现多线程工作:find . -name "*.png" | xargs -P 8 ./compression_png.py,这样一来就会同时运行 8 个进程,也就真的是并行运行了~