本文为博客园作者所写: 一寸HUI,个人博客地址:https://www.cnblogs.com/zsql/
你有批量kill作业吗?有因为删除文件夹的内容太多而报错吗?-bash: /bin/rm: Argument list too long,查找出来的文件怎么直接删除呢?批量执行?并发执行?如果有这样的需求的话,就可以开始学习xargs命令了,本文主要的思路先提供一些简单的使用场景,然后再对xargs命令原理和使用进行阐述。
一、简单使用场景
1.1、使用场景
- 传递参数,从而组合多个命令
- 分隔数据,避免参数过长
- 不支持管道的命令
1.2、具体实例
1.1、批量删除hive用户的所有进程
ps aux | grep ^hive | grep -v grep | awk '{print $2}' | xargs kill -9
1.2、分批次删除logs目录下2020年的所有文件,每批为10个
cd /logs && ls | grep *2020* | xargs -n 10 rm -fr
ls /logs | sed "s:^:`pwd`/:" | grep *2020* | xargs -n 10 rm -fr
1.3、结合find命令进行处理文档,find命令可以查看:linux之find命令详解
find . -name *.log -print0 | xargs rm -f #查找当前目录下的所有log文件,并删除
find ./ -type f -name "*.txt" | xargs -i cp {} /tmp/ #查找txt文件,并复制到/tmp目录下
find ./ -type f -name "*.log" | xargs -i -t tar -zcvf {}.tar.gz {} #压缩日志文件
1.4、批量下载
cat urls.txt | xargs wget
1.5、如果打通了ssh免密,假如有ip:192.168.88.130,192.168.88.131
echo "192.168.88.130,192.168.88.131" | xargs -n 1 -P 2 -I __ip__ scp root@__ip__:/var/log/cron ./__ip__.cron #把这两个机器的cron日志复制到本地,取名为${ip}.cron
二、原理和使用
2.1、使用语法
[root@lgh~]# xargs --help Usage: xargs [-0prtx] [--interactive] [--null] [-d|--delimiter=delim] [-E eof-str] [-e[eof-str]] [--eof[=eof-str]] [-L max-lines] [-l[max-lines]] [--max-lines[=max-lines]] [-I replace-str] [-i[replace-str]] [--replace[=replace-str]] [-n max-args] [--max-args=max-args] [-s max-chars] [--max-chars=max-chars] [-P max-procs] [--max-procs=max-procs] [--show-limits] [--verbose] [--exit] [--no-run-if-empty] [--arg-file=file] [--version] [--help] [command [initial-arguments]]
2.2、原理说明
在1.1中我们说了xargs使用的三个场景,一个是参数太长导致命令不能执行,就像rm一样,如果rm -rf /log/*,正如log目录下有很多很多个文件,这样就会出现/bin/rm: Argument list too long这样的错误,那为啥使用xargs就能删除了呢,因为xargs默认会把参数截取分批进行执行,这里使用了xargs的分割数据和传递参数原理,还有就是有些命令并不支持管道符,像ls命令,但是又想使用一行命令搞定,这样就可以使用xargs配合使用了。比如使用命令:echo text.txt | xargs cat,这样可以把text.txt传递给cat命令作为参数,这样就可以查看该文件了,也就是说xargs完成了两个行为:处理管道传输过来的stdin;将处理后的传递到正确的位置上,还可以将stdin或者文件stdin分割成批,每个批中有很多分割片段,然后将这些片段按批交给xargs后面的命令进行处理,可能看到这里会有点懵逼,那简单点就是:xargs处理的优先级或顺序了:先分割,再分批,然后传递到参数位。
举个例子:假如你有一个蛋糕,你要分给10个孩子去吃,首先第一步要进行切蛋糕(分割)那怎么切呢,切10块还是20块或者其他呢?所以这里就会存在切蛋糕方式的选择(分割方式),切好蛋糕后,小孩子都在不同的地方,你是选择每次送一块蛋糕呢,还是一次送两块呢(这就是分批,每批次传送多少个),送也要找到小孩的位置才能送到他手上吧,(这就是把分好批的文件或数据传递到命令指定的参数的位置),我想大家应该比较容易理解这个了,如果你还是没能理解,多看几遍:xargs处理的优先级或顺序了:先分割,再分批,然后传递到参数位,然后继续看下面的参数例子就懂了
2.3、参数详解
2.3.1、分割参数
分割有三种方法:独立的xargs、xargs -d和xargs -0,后两者可以配合起来使用,既然都可以用来分割,那我们看看分割的方式:
1、xargs分割:将接收到的stdout处理后传递到xargs后面的命令参数位,不写命令时默认的命令是echo,会对空格、tab、换行符,反斜线等进行分割
[root@lgh test]# echo -e "a b c dd y" a b c dd y [root@lgh test]# echo -e "a b c dd y" | xargs #默认会使用echo命令输出,这里的换行符和空格以及制表符都被作为分隔符用来分割了 a b c dd y [root@lgh test]# echo -e "a b c dd y" | xargs echo a b c dd y
将所有空格、制表符和分行符都替换为空格并压缩到一行上显示,这一整行将作为一个整体,这个整体的所有空格属性继承xargs处理前的符号属性(大概理解为,把这些分割好后用自己的所要的“段”替代,干掉别人的心腹(分隔符),换成自己的心腹)
2、xargs -d分割:可以指定分段符,可以是单个符号、字母或数字。如指定字母o为分隔符:xargs -d"o"
[root@lgh test]# echo -e "a bd cod dod y" a bd cod dod y [root@lgh test]# echo -e "a bd cod dod y" |xargs -d 'o' #使用o进行分割,但是这样可能看的不是很清楚 a bd c d d d y
这样看可能就清楚了:
[root@lgh test]# echo -e "a bd cod dod y" |xargs -p -n 1 -d "o" #-p参数交互参数,-n 1执行每批的个数,这些后面会说到 /bin/echo a bd c ?... #打印第一批 /bin/echo d d ?... #打印第二批 /bin/echo d y ?... #打印第三批 /bin/echo ?...
从上就可以看出来是指定的字符"o"进行分割了,使用xargs -d分割,会忽略空格、制表符、分行符等这些符号,会把这些当做内容保留下来,如上面的换行符都有保留下来,只有指定的"o"才是分割符
3、xargs -0分割:可以处理接收的stdin中的null字符( ),其实可以理解是xargs -d的一种特列,等价于xargs -d " "
[root@mvxl2685 test]# echo -e "1 bbb
uu dddd"
1 bbb
uudddd
[root@mvxl2685 test]# echo -e "1 bbb
uu dddd" | xargs -0
1 bbb
uu dddd
[root@mvxl2685 test]# echo -e "1 bbb
uu dddd" | xargs -0 -p -n 1
/bin/echo 1 bbb
uu ?... #第一批
/bin/echo dddd
?... #第二批
/bin/echo ?...
上面三种分割方式,使用最多的也就是默认的xargs了
分割行为 |
特殊符号处理方式 |
分段方法 |
配合分批选项 |
分批方法 |
xargs |
空格、制表符、分行符替换为空格,引号和反斜线删除。处理完后只有空格。如果空格、制表符和分行符使用引号包围则可以保留 |
结果继承处理前的符号性质(文本符号还是标记意义符号)。 |
-n |
以分段结果中的每个空格分段,进而分批。不管是文本还是标记意义的空格,只要是空格 |
-L、-i |
以标记意义上的空格分段,进而分批 |
|||
不指定 |
结果作为整体输出 |
|||
xargs -d |
xargs -d 不处理文本意义上的符号,所有标记意义上的符号替换为换行符 ,将-d指定的分割符替换为标记意义上的空格。 结果中除了最后的空行和-d指定的分割符位的分段空格,其余全是文本意义上的符号 |
按照-d指定的符号进行分段,每个段中可能包含文本意义上的空格、制表符、甚至是分行符。 |
-n、-L、-i |
以标记意义上的符号(即最后的空行和-d指定分隔符位的空格)分段,进而分批。分段结果中保留所有段中的符号,包括制表符和分行符。 |
不指定 |
结果作为整体输出 |
|||
xargs -0 |
不处理文本意义上的符号,将非 的标记意义上的符号替换为 ,将 替换为空格。 结果中除了最后空行和 位的空格,其余都是文本意义上的符号 |
以替换 位的空格分段,每个段中可能包含文本意义上的空格、制表符、甚至是分行符。 如果没检测到 ,则只有一个不可分割的段。 |
-n、-L、-i |
检测到 时,以标记意义上的符号(即最后的空行和 位的空格)分段,进而分批。分段结果中保留所有段中的符号,包括制表符和分行符。 |
未检测到 时,整个结果作为不可分割整体,使用分批选项是无意义的 |
||||
不指定 |
结果作为整体输出 |
2.3.2、分批参数
上面一节中我们知道怎么切蛋糕了(分割),接下来我们就怎么把这些分割好的内容组装成批次。可以使用-n和-L两个参数,那具体他们有什么区别呢?请继续往下看:
1、使用-n分批
假如有文件夹test:
[root@lgh test]# ll total 0 -rw-r--r-- 1 root root 0 Dec 4 14:33 a -rw-r--r-- 1 root root 0 Dec 4 14:33 b -rw-r--r-- 1 root root 0 Dec 4 14:33 c -rw-r--r-- 1 root root 0 Dec 4 14:33 dd -rw-r--r-- 1 root root 0 Dec 4 14:33 gg -rw-r--r-- 1 root root 0 Dec 4 14:33 u t.txt #这是个特殊文件,有空格的文件名 -rw-r--r-- 1 root root 0 Dec 4 14:33 uu
接下我们使用-n分批会有怎样的效果呢?
[root@lgh test]# ls | xargs -n 2 #每两个作为一个批次 a b c dd gg u #这里把u t.txt文件拆到两个批次中了,这并不是我们想要的 t.txt uu
xargs -n分两种情况:和独立的xargs一起使用,这时按照每个空格分段划批;和xargs -d或xargs -0一起使用,这时按段分批,即不以空格、制表符和分行符分段划批
2、使用-L分批
[root@lgh test]# ls | xargs -L 2 #每两个作为一个批次 a b c dd gg u t.txt #这里就没有拆分u t.txt文件 uu
-n选项类似,唯一的区别是-L永远是按段划批,而-n在和独立的xargs一起使用时是按空格分段划批的
2.3.3、位置传递参数
xargs -i和xargs -I选项在逻辑上用于接收传递的分批结果,如果不使用这两个选项,则默认是将分割后处理后的结果整体传递到命令的最尾部,有时候可能需要到多个位置,或者不是最后一个位置,例如cp命令一样,所以这两个参数很重要。
使用xargs -i时以大括号{}作为替换符号,传递的时候看到{}就将被结果替换。可以将{}放在任意需要传递的参数位上,如果多个地方使用{}就实现了多个传递
假如有目录test:
[root@lgh test]# ll total 0 -rw-r--r-- 1 root root 0 Dec 4 14:51 10.log -rw-r--r-- 1 root root 0 Dec 4 14:51 1.log -rw-r--r-- 1 root root 0 Dec 4 14:51 2.log -rw-r--r-- 1 root root 0 Dec 4 14:51 3.log -rw-r--r-- 1 root root 0 Dec 4 14:51 4.log -rw-r--r-- 1 root root 0 Dec 4 14:51 5.log -rw-r--r-- 1 root root 0 Dec 4 14:51 6.log -rw-r--r-- 1 root root 0 Dec 4 14:51 7.log -rw-r--r-- 1 root root 0 Dec 4 14:51 8.log -rw-r--r-- 1 root root 0 Dec 4 14:51 9.log
现在需要把它们全部备份起来,编程*.log.bak文件
[root@lgh test]# ls | xargs -i mv {} {}.bak #这里使用-i接收,然后使用{}指定位置 [root@lgh test]# ll total 0 -rw-r--r-- 1 root root 0 Dec 4 14:51 10.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 1.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 2.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 3.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 4.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 5.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 6.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 7.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 8.log.bak -rw-r--r-- 1 root root 0 Dec 4 14:51 9.log.bak
-I则可以指定其他的符号、字母、数字作为替换符号,例如xargs -I
[root@lgh test]# ls | xargs -I bb mv bb bb.I #这里使用-I参数指定bb为接收替代符 [root@lgh test]# ll total 0 -rw-r--r-- 1 root root 0 Dec 4 14:51 10.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 1.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 2.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 3.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 4.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 5.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 6.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 7.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 8.log.bak.I -rw-r--r-- 1 root root 0 Dec 4 14:51 9.log.bak.I
注意:-i、-L、-n这三个参数在一起,都会被最后一个覆盖,也就是一起使用的时候,只有最后一个生效
2.3.4、其他参数
上面已经把最重要的一些参数介绍完了,我们看看其他参数
1、-p和-t:交互参数,可以用于前期不确定执行过程,用来测试自己写的代码是否符合最终的执行命令
-p是询问是否打印,y键表示打印,回车表示不打印
[root@lgh test]# ls | xargs -n 3 -p /bin/echo 10.log.bak.I 1.log.bak.I 2.log.bak.I ?...y #询问打印,按下y /bin/echo 3.log.bak.I 4.log.bak.I 5.log.bak.I ?...10.log.bak.I 1.log.bak.I 2.log.bak.I #打印出上一次询问的值,然后继续询问下一个批次是否打印,按下回车,不打印输出 /bin/echo 6.log.bak.I 7.log.bak.I 8.log.bak.I ?... /bin/echo 9.log.bak.I ?...
-t是先把执行的语句打印出来,然后把要输出的内容打印出来
[root@lgh test]# ls | xargs -n 3 -t /bin/echo 10.log.bak.I 1.log.bak.I 2.log.bak.I #打印执行的语句 10.log.bak.I 1.log.bak.I 2.log.bak.I #打印执行语句的结果 /bin/echo 3.log.bak.I 4.log.bak.I 5.log.bak.I 3.log.bak.I 4.log.bak.I 5.log.bak.I /bin/echo 6.log.bak.I 7.log.bak.I 8.log.bak.I 6.log.bak.I 7.log.bak.I 8.log.bak.I /bin/echo 9.log.bak.I 9.log.bak.I
2、-P:批量执行参数(并发,一起执行)哈哈,反正就是同时执行
在执行某一个命令的时候,后面很多参数的时候,例如:rm log/* 会对log下的每一个目录进行依次删除,就算使用xargs的分批执行,还是一个一个执行的,并不会提高效率,接下来该-P参数出场了
"-P N"选项可以指定并行处理的进程数量为N。不指定"-P"时,默认为1个处理进程,也就是串行执行。指定为0时,将尽可能多地开启进程数量
[root@lgh ~]# time echo {1..3} | xargs -n 1 sleep #不使用-P,并每个批次为1,总共的执行时间为6秒 real 0m6.005s user 0m0.001s sys 0m0.001s [root@lgh ~]# time echo {1..3} | xargs -n 3 sleep #不使用-P,每个批次为3,总共执行时间为6秒,分批不能提高速度 real 0m6.003s user 0m0.000s sys 0m0.002s [root@lgh ~]# time echo {1..3} | xargs -n 3 -P 3 sleep #使用-P,每个批次为3,说明只有一个批次,所以一个线程需要一次执行所有的命令,所以还是6秒,没有达到并发的效果 real 0m6.003s user 0m0.001s sys 0m0.000s [root@lgh ~]# time echo {1..3} | xargs -n 1 -P 3 sleep #使用-P,每个批次为1,所以可以同时执行命令,执行时间为3秒 real 0m3.003s user 0m0.001s sys 0m0.001s
很多时候,执行大量命令的时候可以使用-P提高效率
2.4、总结
xargs命令很强大,你值得拥有!!!如果使用的得当不仅可以提高逼格,还可以提高效率,能够做一些原本命令不能做到的事情,好好学号xargs何乐而不为呢?
xargs的总结:分割(xargs,xargs -d,xargs -0)、分批(-n,-L)、传递到指定位置(-i,-I)
参考:
https://www.cnblogs.com/f-ck-need-u/p/5925923.html#auto_id_9