2023年7月10日发(作者:)
xargs原理剖析及⽤法详解学习这个xargs花了很长时间,在⽹上翻了很久也查了很多书关于xargs的介绍,都只是简单的介绍了它的⼏个⽤法,却没有介绍它⼯作的原理,man也只有简单的介绍,并没有说各个选项之间配合时的情况。所以我只能⾃⼰探索了,探索的路上确实充满了荆棘,不断的总结却不断的被实验推翻,每当以为⾃⼰得出了结论,却往往发现不够完善,所以我⾃⼰也是边测试边删改完成这篇学习记录,但是不得不说这过程充满了乐趣。个⼈感觉xargs的基本⽤法很简单,它的选项实现的功能也很简单,但是多个选项配合时问题就变得很难很难,经常发现结果和预期不同。这⼀整篇是我个⼈的总结和记录,由于完全是⾃⼰⼀个⼈在短短⼏天内探索出来的,所以难免会有所遗漏、错误,甚⾄可能是误⼈的结论,万望见谅。如果有朋友发现了其中的问题盼请不吝指出,本⼈将感激不尽。1.1 为什么需要xargs管道实现的是将前⾯的stdout作为后⾯的stdin,但是有些命令不接受管道的传递⽅式,最常见的就是ls命令。有些时候命令希望管道传递的是参数,但是直接⽤管道有时⽆法传递到命令的参数位,这时候需要xargs,xargs实现的是将管道传输过来的stdin进⾏处理然后传递到命令的参数位上。也就是说xargs完成了两个⾏为:处理管道传输过来的stdin;将处理后的传递到正确的位置上。可以试试运⾏下⾯的⼏条命令,应该能很好理解xargs的作⽤了:[root@xuexi tmp]# echo "/etc/inittab" | cat # 直接将标准输⼊的内容传递给cat[root@xuexi tmp]# echo "/etc/inittab" | xargs cat # 将标准输⼊的内容经过xargs处理后传递给cat[root@xuexi tmp]# find /etc -maxdepth 1 -name "*.conf" -print0 | xargs -0 -i grep "hostname" -l {} # 将搜索的⽂件传递给grep的参数位进⾏搜索,若不使⽤xargs,则xargs的作⽤不仅仅限于简单的stdin传递到命令的参数位,它还可以将stdin或者⽂件stdin分割成批,每个批中有很多分割⽚段,然后将这些⽚段按批交给xargs后⾯的命令进⾏处理。通俗的讲就是原来只能⼀个⼀个传递,分批可以实现10个10个传递,每传递⼀次,xargs后⾯的命令处理这10个中的每⼀个,处理完了处理下⼀个传递过来的批,如下图。但是应该注意的是,尽管实现了分批处理,但是默认情况下并没有提⾼任何效率,因为分批传递之后还是⼀次执⾏⼀个。⽽且有时候分批传递后是作为⼀个参数的整体,并不会将分批中的信息分段执⾏。这样看来,实现分批传递的⽬的仅仅是为了解决⼀些问题。但事实上,xargs提供了"-P"选项,⽤于指定并⾏执⾏的数量(默认只有⼀个处理进程,不会提升效率,可以指定为N个⼦进程,或者指定为0表⽰尽可能多地利⽤CPU),这样就能让分批操作更好地利⽤多核cpu,从⽽提升效率。例如上⾯分成了两批,指定"-P 2"可以并发执⾏这两个批,⽽⾮执⾏完第⼀批再执⾏第⼆批。关于并⾏处理的详细内容,见后⽂:。剩下的就是处理xargs的细节问题了,⽐如如何分割(xargs、xargs -d、xargs -0),分割后如何划批(xargs -n、xargs -L),参数如何传递(xargs -i)。另外xargs还提供询问交互式处理(-p选项)和预先打印⼀遍命令的执⾏情况(-t选项),传递终⽌符(-E选项)等。其实这⾥已经暗⽰了xargs处理的优先级或顺序了:先分割,再分批,然后传递到参数位。分割有三种⽅法:独⽴的xargs、xargs -d和xargs -0。后两者可以配合起来使⽤,之所以不能配合独⽴的xargs使⽤,答案是显然的,指定了-d或-0选项意味着它不再是独⽴的。分批⽅法从逻辑上说是两种:-n选项和-L选项。但我觉得还应该包含传递阶段的选项-i。假如-i不是分批选项,则它将接收分批的结果。然⽽事实并⾮如此,当-i选项指定在-n和-L选项之后,会覆盖-n或-L。后⽂中我将其当成分批选项来介绍和说明。当然上述只是⼀个概括,更具体的还要看具体的选项介绍,⽽且很可能⼀个xargs中⽤不到这么多选项,但是理解这个很重要,否则在分割分批和传递上很容易出现疑惑。1.2 ⽂本意义上的符号和标记意义上的符号在解释xargs和它的各种选项之前,我想先介绍⼀个贯穿xargs命令的符号分类:⽂本意义上的空格、制表符、反斜线、引号和⾮⽂本意义上的符号。我觉得理解它们是理解xargs分割和分批原理的关键。⽂本意义上的空格、制表符、反斜线、引号:未经处理就已经存在的符号,例如⽂本的内容中出现这些符号以及在⽂件名上出现了这些符号都是⽂本意义上的。与之相对的是⾮⽂本意义的符号,由于在⽹上没找到类似的⽂章和解释,所以我个⼈称之为标记意义上的符号:处理后出现的符号,例如ls命令的结果中每个⽂件之间的制表符,它原本是不存在的,只是ls命令处理后的显⽰⽅式。还包括每个命令结果的最后的换⾏符,⽂件内容的最后⼀⾏结尾的换⾏符。如下图,属于标记意义上的符号都⽤红⾊圆圈标记出来了。其实它们的关系有点类似于字⾯意义的符号和特殊符号之间的关系,就像有时候特殊符号需要进⾏转义才能表⽰为普通符号。因为翻了百度、⾕歌和⼀些书都没说这些⽅⾯的分类。但⽂本和⾮⽂本的符号在xargs分割的时候确实是区别对待的,所以我觉得有必要给个称呼好引⽤并说明它们,也就是说以上称呼完全是我个⼈的称呼。1.3 分割⾏为之:xargs[root@xuexi tmp]# cd /tmp[root@xuexi tmp]# rm -fr *[root@xuexi tmp]# mkdir a b c d test logdir shdir[root@xuexi tmp]# touch "one "[root@xuexi tmp]# touch logdir/{1..10}.log[root@xuexi tmp]# touch shdir/{1..5}.sh[root@xuexi tmp]# echo "the second sh the second line" > shdir/
[root@xuexi tmp]# cat <
> the first sh> the second line> eof对于xargs,它将接收到的stdout处理后传递到xargs后⾯的命令参数位,不写命令时默认的命令是echo。[root@xuexi tmp]# cat shdir/ | xargsthe first sh the second line[root@xuexi tmp]# cat shdir/ | xargs echothe first sh the second line将分⾏处理掉不是echo实现的,⽽是管道传递过来的stdin经过xargs处理后的:将所有空格、制表符和分⾏符都替换为空格并压缩到⼀⾏上显⽰,这⼀整⾏将作为⼀个整体,这个整体的所有空格属性继承xargs处理前的符号属性,即原来是⽂本意义的或标记意义的在替换为空格后符号属性不变。这个整体可能直接交给命令或者作为stdout通过管道传递给管道右边的命令,这时结果将作为整体传递,也可能被xargs同时指定的分批选项分批处理。如果想要保存制表符、空格等特殊符号,需要将它们⽤单引号或双引号包围起来,但是单双引号(和反斜线)都会被xargs去掉。另外经过我的测试,单引号和双引号的存在让处理变的很不受控制,经常会影响正常的分割和处理。如果不指定分批选项,xargs的⼀整⾏结果将作为⼀个整体输出,⽽不是分隔开的。也许看处理的结果感觉是分开处理的,例如下⾯的第⼀个命令,但是这是因为ls允许接受多个空格分开的参数,执⾏第⼆个命令,可以证明它确实是将整⾏作为整体传输给命令的。[root@xuexi tmp]# find /tmp -maxdepth 1 | xargs ls/tmp/
/tmp:a b c d logdir shdir test
/tmp/a:
/tmp/b:
/tmp/c:
/tmp/d:
/tmp/.ICE-unix:
/tmp/logdir:
/tmp/shdir: hell
/tmp/test:[root@xuexi tmp]# find /tmp -maxdepth 1 | xargs -p ls # -p选项后⾯有解释ls /tmp /tmp/ /tmp/logdir /tmp/b /tmp/test /tmp/d /tmp/vmware-root /tmp/ /tmp/c /tmp/shdir /tmp/a /tmp/one /tmp/.ICE-unix ?...如果对独⽴的xargs指定分批选项,则有两种分批可能:指定-n时按空格分段,然后划批,不管是⽂本意义的空格还是标记意义的空格,只要是空格都是-n的操作对象;指定-L或者-i时按段划批,⽂本意义的符号不被处理。[root@xuexi tmp]# ls #one 是⼀个⽂件的⽂件名,只是包含了空格a b c d logdir one shdir test vmware-root [root@xuexi tmp]# ls | xargs -n 2a bc dlogdir one # one和分割开了,说明-n是按空格分割的 testvmware-root [root@xuexi tmp]# ls | xargs -L 2a bc dlogdir one # one 作为⼀个分段,⽂件名中的空格没有分割这个段shdir t [root@xuexi tmp]# ls | xargs -i -p echo {}echo a ?...echo b ?...echo c ?...echo d ?...echo logdir ?...echo one ?... # one 也没有被⽂件名中的空格分割echo shdir ?...echo ?...echo test ?...echo vmware-root ?...echo ?...1.4 使⽤xargs -p或xargs -t观察命令的执⾏过程使⽤-p选项是交互询问式的,只有每次询问的时候输⼊y(或yes)才会执⾏,直接按enter键是不会执⾏的。使⽤-t选项是在每次执⾏xargs后⾯的命令都会先在stderr上打印⼀遍命令的执⾏过程然后才正式执⾏。使⽤-p或-t选项就可以根据xargs后命令的执⾏顺序进⾏推测,xargs是如何分段、分批以及如何传递的,这通过它们有助于理解xargs的各种选项。[root@xuexi tmp]# ls | xargs -n 2 -t/bin/echo a b # 先打印⼀次命令,表⽰这⼀次只echo两个参数:a和ba b/bin/echo c d # 表⽰这次只打印c和dc d/bin/echo logdir onelogdir one/bin/echo shdir/bin/echo test/bin/echo vmware-rootvmware-root[root@xuexi tmp]# ls | xargs -n 2 -p/bin/echo a b ?...y # 询问是否echo a b/bin/echo c d ?...a by # 询问是否echo c d,后⾯的...a b指⽰了echo c d是在前⼀个结果的基础上接着执⾏的/bin/echo logdir one ?...c dy/bin/echo shdir ?...logdir oney/bin/echo test ?... shdiry/bin/echo vmware-root ?... testyvmware-root从上⾯的-t和-p的结果上都可以知道每次传递两个参数。1.5 分割⾏为之:xargs -dxargs -d有如下⾏为:
xargs -d可以指定分段符,可以是单个符号、字母或数字。如指定字母o为分隔符:xargs -d"o"。
xargs -d是分割阶段的选项,所以它优先于分批选项(-n、-L、-i)。
xargs -d不是先xargs再-d处理的,它是区别于独⽴的xargs的另⼀个分割选项。xargs -d整体执⾏有⼏个阶段:
替换:将接收stdin的所有的标记意义的符号替换为n,替换完成后所有的符号(空格、制表符、分⾏符)变成字⾯意义上的普通符号,即⽂本意义的符号。
分段:根据-d指定的分隔符进⾏分段并⽤空格分开每段,由于分段前所有符号都是普通字⾯意义上的符号,所以有的分段中可能包含了空格、制表符、分⾏符。也就是说除了-d导致的分段空格,其余所有的符号都是分段中的⼀部分。
输出:最后根据指定的分批选项来输出。这⾥需要注意,分段前后有特殊符号时会完全按照符号输出。从上⾯的阶段得出以下两结论:(1)xargs -d会忽略⽂本意义上的符号。对于⽂本意义上的空格、制表符、分⾏符,除⾮是-d指定的符号,否则它们从来不会被处理,它们⼀直都是每个分段⾥的⼀部分;(2)由于第⼀阶段标记意义的符号会替换为分⾏符号,所以传⼊的stdin的每个标记意义符号位都在最终的xargs -d结果上分⾏了,但是它们已经是分段中的普通符号了,除⾮它们是-d指定的符号。例如对ls的结果指定"o"为分隔符。[root@xuexi tmp]# lsa b c d logdir one shdir test vmware-root[root@xuexi tmp]# ls | xargs -d"o" #指定字母"o"为分隔符分段结果如图所⽰,图中每个封闭体都是⼀个分段,这些分段⾥可能包含了分⾏,可能包含了空格。如果使⽤xargs -d时不指定分批选项,则整个结果将作为整体输出。[root@xuexi tmp]# ls | xargs -d"o" -p/bin/echo abcdl gdir ne space.l tvmware-r ...如果指定了分批选项,则按照-d指定的分隔符分段后的段分批,这时使⽤-n、-L或-i的结果是⼀样的。例如使⽤-n选项来观察是如何分批的。[root@xuexi tmp]# ls | xargs -d"o" -n 2 -t/bin/echo abcdl gdir # 每两段是⼀个批。
abcdl gdir # 注意这⾥有个空⾏。是因为段的分隔符处于下⼀段的⾏开头,它的前⾯有个n符号会按符号输出。/bin/echo ne space.l tvmware-r # 打印中间两段ne space.l tvmware-r/bin/echo t # 打印最后⼀段,
t # 注意t前⾯有空格,因为是两个分隔符o连在⼀起分割的,所以前⾯有个空格需要输出。
下⾯是最终显⽰结果。[root@xuexi tmp]# ls | xargs -d"o" -n 2abcdl gdir
ne space.l tvmware-r t
再看看-n 1的输出。[root@xuexi tmp]# ls | xargs -d"o" -n 1abcdlgdir
ne tvmware-r
t
[root@xuexi tmp]#1.6 分割⾏为之:xargs -0xargs -0的⾏为和xargs -d基本是⼀样的,只是-d是指定分隔符,-0是指定固定的0作为分隔符。其实xargs -0就是特殊的xargs -d的⼀种,它等价于xargs -d"0"。xargs -0⾏为如下:
xargs -0是分割阶段的选项,所以它优先于分批选项(-n、-L、-i)。
xargs -0不是先xargs再-0处理的,它是区别于独⽴的xargs的另⼀个分割选项。
xargs -0可以处理接收的stdin中的null字符(0)。如果不使⽤ -0选项或- -null选项,检测到0后会给出警告提醒,并只向命令传递⾮0段。xargs -0和- -null是⼀样的效果。xargs -0整体执⾏有⼏个阶段:
替换:将接收stdin的所有的标记意义的符号替换为n,替换完成后所有的符号(空格、制表符、分⾏符)变成字⾯意义上的普通符号,即⽂本意义的符号。
分段:将检测到的null字符(0)使⽤标记意义上的空格来分段,由于分段前所有符号都是普通字⾯意义上的符号,所以有的分段中可能包含了空格、制表符、分⾏符。也就是说除了-0导致的分段空格,其余所有的符号都是分段中的⼀部分。如果没有检测到0,则接收的整个stdin将成为⼀个不可分割的整体,任何分批选项都不会将其分割开,因为它只有⼀个段。
输出:最后根据指定的分批选项来输出。这⾥需要注意,分段前后有特殊符号时会完全按照符号输出。根据上⾯的结论可知,xargs -0会忽略所有⽂本意义上的符号,它的主要⽬的是处理0符号。[root@xuexi tmp]# touch "one "[root@xuexi tmp]# ls | tr " " "t" | xargs -0 #忽略⽂本意义上的制表符abcdlogdirone tvmware-root # 注意有空⾏,因为命令结尾是⼀个标记意义上换⾏符号[root@xuexi tmp]# ls | tr " " " " | xargs -0 #忽略⽂本意义上的空格abcdlogdirone tvmware-root # 注意有空⾏如果检测到0⽽没有使⽤-0或--null处理则给出警告。注意警告后执⾏哪些⽂件。[root@xuexi tmp]# ls | tr " " "0" # 这⾥实际上是tvmware-root[root@xuexi tmp]# ls | tr " " "0" | xargsxargs: Warning: a NUL character occurred in the input. It cannot be passed through in the argument list. Did you mean to use the --null option?a b c d logdir one shdir test vmware-root # 执⾏时将忽略了,其余都执⾏再例如,将所有的换⾏符换成null字符,结果中除了最前⾯的字母a和由于空格⽽不被0影响的,其余的由于全部有0全部被忽略。[root@xuexi tmp]# ls | tr "n" "0"a bcdlogdirone tvmware-root # 只有a的前⾯和的前⾯是没有0的[root@xuexi tmp]# ls | tr "n" "0" | xargsxargs: Warning: a NUL character occurred in the input. It cannot be passed through in the argument list. Did you mean to use the --null option?a # 所以只执⾏这两个使⽤-0或--null来解决问题,也可以使⽤等价的xargs -d"0"来解决。[root@xuexi tmp]# ls | tr "n" "0" | xargs -0或者[root@xuexi tmp]# ls | tr "n" "0" | xargs -d"0"a b c d logdir one shdir test vmware-root如果使⽤xargs -0时不指定分批选项(-n、-L、-i),则处理后的结果将作为⼀个整体输出。如果指定了分批选项,并且检测到了null字符,则以0位的空格分段划批,这时使⽤-n、-L或-i的结果是⼀样的。例如使⽤-n选项来观察是如何分批的。[root@xuexi tmp]# ls | tr "n" "0" | xargs -0 -n 3a b cd logdir one ir testvmware-root 如果指定了分批选项,但没有检测到null字符,则整个结果将称为⼀个不可分割整体,这时使⽤分批选项是完全⽆意义的。[root@xuexi tmp]# ls | xargs -0 -n 3 -p/bin/echo abcdlogdirone ...1.7 分批⾏为分批⽤于指定每次传递多少个分段。有三种分批选项:-n,-L和-i。在本⽂的开头已经指明了为什么-i是分批选项,但是这⾥还是要介绍它逻辑上定义的功能:参数替换。既然三种选项都是分批选项,如果在⼀个xargs中使⽤了多个分批选项,则它们之间必然会冲突,它们的规则是写在后⾯的⽣效,前⾯的分批选项被忽略。1.7.1 xargs -nxargs -n分两种情况:和独⽴的xargs⼀起使⽤,这时按照每个空格分段划批;和xargs -d或xargs -0⼀起使⽤,这时按段分批,即不以空格、制表符和分⾏符分段划批。[root@xuexi tmp]# ls | xargs -n 3 -p #和独⽴的xargs⼀起使⽤,以空格分段划批/bin/echo a b c ?.../bin/echo d logdir one ?... # one和被割开了/bin/echo shdir ?.../bin/echo test vmware-root ?.../bin/echo ?...[root@xuexi tmp]# ls | xargs -d"o" -n 3 -p # 和xargs -d⼀起使⽤,按段分批/bin/echo abcdl gdir ne space.l ?.../bin/echo tvmware-r .../bin/echo ?...1.7.2 xargs -L和-n选项类似,唯⼀的区别是-L永远是按段划批,⽽-n在和独⽴的xargs⼀起使⽤时是按空格分段划批的。该选项的⼀个同义词是-l,但是man推荐使⽤-L替代-l,因为-L符合POSIX标准,⽽-l不符合。使⽤--max-lines也可以。也许你man xargs时发现-L选项是指定传递时最⼤传递⾏数量的,man的结果如下图。但是通过下⾯的实验可以验证其实-L是指定传递的最⼤段数,也就是分批。[root@xuexi tmp]# ls | xargs -L 3 -p #如果是指定传递的最⼤⾏数量,则⼀⾏就输出完了,这⾥却分了多⾏输出/bin/echo a b c ?...
/bin/echo d logdir one ?... # 这⾥可以证明-L和-n的区别/bin/echo shdir test ?.../bin/echo vmware-root ?...[root@xuexi tmp]# ls | xargs -d"o" -L 3 -p # 这就更能证明是指定最⼤传递的段数量了/bin/echo abcdl gdir ne space.l ?.../bin/echo tvmware-r ...1.7.3 xargs -i和xargs -Ixargs -i选项在逻辑上⽤于接收传递的分批结果。如果不使⽤-i,则默认是将分割后处理后的结果整体传递到命令的最尾部。但是有时候需要传递到多个位置,不使⽤-i就不知道传递到哪个位置了,例如重命名备份的时候在每个传递过来的⽂件名加上后缀.bak,这需要两个参数位。使⽤xargs -i时以⼤括号{}作为替换符号,传递的时候看到{}就将被结果替换。可以将{}放在任意需要传递的参数位上,如果多个地⽅使⽤{}就实现了多个传递。xargs -I(⼤写字母i)和xargs -i是⼀样的,只是-i默认使⽤⼤括号作为替换符号,-I则可以指定其他的符号、字母、数字作为替换符号,但是必须⽤引号包起来。man推荐使⽤-I代替-i,但是⼀般都使⽤-i图个简单,除⾮在命令中不能使⽤⼤括号,如touch {1..1000}.log时⼤括号就不能⽤来做替换符号。例如下⾯的重命名备份过程。[root@xuexi tmp]# ls logdir/ [root@xuexi tmp]# ls logdir/ | xargs -i mv ./logdir/{} ./logdir/{}.bak # 将分段传递到多个参数位[root@xuexi tmp]# ls logdir/ 但是我将“-i”选项划分在分批选项⾥,它默认⼀个段为⼀个批,每次传递⼀个批也就是传递⼀个段到指定的⼤括号{}位上。在稍后的分批选项的⽣效规则部分我会给出我的理由。由于-i选项是按分段来传递的。所以尽管看上去等价的xargs echo和xargs -i echo {}并不等价。[root@xuexi tmp]# ls | xargs echoa b c d logdir one shdir test vmware-root[root@xuexi tmp]# ls | xargs -i echo {}abcdlogdirone tvmware-root既然使⽤-i后是分段传递的,这就意味着指定了它就⽆法实现按批传递多个参数了;并且如果使⽤多个⼤括号,意味着必须使⽤-i,那么也⽆法分批传递。例如,想将数字1-10每3个数显⽰在start和end之间。效果如下:start 1 2 3 endstart 4 5 6 endstart 7 8 9 endstart 10 end由于指定了参数传递位置,所以必须使⽤-i,那么就⽆法⼀次传递3个数。要解决这个问题,就要想办法让每三个数分⼀次段然后使⽤-i传递,⽅法也就随之⽽来了。可以将每三个数分⼀次⾏写⼊⼀个⽂件。如:[root@xuexi tmp]# cat <
在此基础上创建⼀个.sh⽂件,这个⽂件将奇形怪状,因为⽂件名竟然包含了分⾏符(Linux中⽂件名除了"/"和"0"外所有字符都允许包含在内)。[root@xuexi tmp]# ls | xargs -0 -i touch {}.sh[root@xuexi tmp]# lsa b d one vmware-roota?b?c?d?logdir?one ?shdir??test?vmware-root?.sh c logdir shdir test看上去只是有⼏个问号,但是使⽤?是⽆法定位它的。[root@xuexi tmp]# find -name "*[?]*" #搜索没结果或者[root@xuexi tmp]# rm -rf a #按两次tab键a/a^Jb^Jc^Jd^Jlogdir^Jone ^Jshdir^^Jtest^Jvmware-root^现在使⽤xargs就可以轻松显⽰它的⽂件名。[root@xuexi tmp]# ls | xargs -0aabcdlogdirone ogdirone tvmware-root不能直接使⽤xargs显⽰,因为它会压缩空⽩符号成空格。[root@xuexi tmp]# ls | xargsa a b c d logdir one shdir test vmware-root .sh b c d logdir one shdir test vmware-root删除它。[root@xuexi tmp]# rm -f a*.sh如果想创建⽂件名只包含下⾯结果的abcd前四⾏的.sh⽂件呢?[root@xuexi tmp]# ls | xargs -0abcdlogdirone tvmware-root参考下⾯的。[root@xuexi tmp]# ls | xargs -n 1 -e"logdir" | xargs -0 -i touch {}.sh这就需要理解前⾯介绍的xargs的分割和传递⽅法了。也可以使⽤下⾯更简单容易理解的:[root@xuexi tmp]# ls | head -n 4 | xargs -0 -i touch {}.sh[root@xuexi tmp]# echo -e "anbncnd" | xargs -0 -i touch {}.log那么以相同的⽅法创建⽂件名中包含制表符的⽂件就easy了。[root@xuexi tmp]# echo -e "atbtctd" | xargs -0 -i touch {}.log1.13 ⾼速并发处理之:xargs -P使⽤xargs的分批⾏为,除了可以解决⼀些问题,还可以⼀次性将多个分批交给不同进程去处理,这些进程可以使⽤多个cpu执⾏,效率可谓⼤幅提⾼。"-P N"选项可以指定并⾏处理的进程数量为N。不指定"-P"时,默认为1个处理进程,也就是串⾏执⾏。指定为0时,将尽可能多地开启进程数量。当xargs正在运⾏时(也就是还有分批正在处理),可以发送SIGUSR1信号给xargs进程,表⽰增加⼀个处理进程,同样,可以向xargs进程发送SIGUSR2进程,表⽰减少⼀个处理进程。但需要注意,即使发送SIGUSR2信号,xargs也不会中断正在执⾏任务的进程,也就是说,在某个进程处理当前分批任务结束之前,不会被中断,只有当前分批任务执⾏完毕,准备接下⼀个分批任务时,才会被xargs给杀掉。例如,⼀个简单的sleep命令,在不使⽤"-P"的时候,默认是⼀个进程按批的先后进⾏处理:[root@xuexi ~]# time echo {1..4} | xargs -n 1 sleep
real 0m10.011suser 0m0.000ssys 0m0.011s总共⽤了10秒,因为每批传⼀个参数,第⼀批睡眠1秒,然后第⼆批睡眠2秒,依次类推,还有3秒、4秒,共1+2+3+4=10秒。如果使⽤-P指定4个处理进程:[root@xuexi ~]# time echo {1..4} | xargs -n 1 -P 4 sleep
real 0m4.005suser 0m0.000ssys 0m0.007s结果总共才⽤了4秒,因为这4个分批同时交给了4个进程同时处理,所以取最长睡眠时间。以下是⼀次并⾏执⾏过程中,CPU的使⽤情况:[root@xuexi ~]# ps -eo pid,args,psr,pcpu | grep slee[p] 25566 xargs -n 1 -P 5 sleep 3 0.0 25567 sleep 20 1 0.0 25568 sleep 21 2 0.0 25569 sleep 22 0 0.0 25570 sleep 23 2 0.0 25571 sleep 24 3 0.0在上⾯的结果中,启动了5个sleep进程,这5个进程分别⽤了cpu0、cpu1、cpu2和cpu3共4个cpu,因为我的虚拟机只给分配了4核⼼cpu。那么,xargs的哪些选项可以通过"-P"的并⾏能⼒来提升效率?其实,只要能分批的选项,都可以使⽤"-P",包括"-n"、"-L"和"-i"。在man xagrs中,只提到了"-n"和"-L"可以结合"-P",并没有提到"-i",但我前⾯已经验证过了,"-i"其实也是分批⾏为,也能结合"-P"的并⾏功能使⽤。下⾯的⽰例,可以验证"-i -P"结合:[root@xuexi ~]# time echo -n {1..4} | xargs -d" " -i -P 4 sleep {}
real 0m4.003suser 0m0.000ssys 0m0.005s如果需要发送信号,来增、减并⾏进程数量,可以向xargs进程发送SIGUSR1和SIGUSR2信号,例如:kill -USR1 `pgrep -f "xargs"`虽然xargs提供了这样的并⾏处理能⼒,但说实话,⽤到的机会并不多,它毕竟只是⼀个参数传递⼯具。我也专门写了⼀篇关于xargs⾼效并⾏的⽂章,见。另⼀个gnu⼯具parallel(装上epel源,yum -y install parallel即可)在并⾏处理上⽤的⽐较多,⽐如对⼀个巨⼤的⽂件利⽤sort进⾏排序时,使⽤parallel并⾏排序,可以⼤幅提升效率,即使sort⾃⾝已经⾜够完美。⾮常幸运的是,在你把xargs学到了这⾥,使⽤parallel将⾮常简单,因为它的选项和⾏为模式和xargs是基本⼀致的。1.14 xargs⼀次性传递多个参数默认情况下,xargs每次只能传递⼀条分割的数据到命令⾏中作为参数。但有时候想要让xargs⼀次传递2个、3个参数到命令⾏中。例如有⼀个⽂件保存了wget想要下载的⼤量链接和链接对应要保存的⽂件名,⼀⾏链接⼀⾏⽂件名。格式如下:/a1filename1/a2filename2/a3filename3现在想要通过读取这个⽂件,将每⼀个URL和对应的⽂件名传递给wget去下载:wget '{URL}' -O '{FILENAME}'xargs⾃⾝的功能⽆法⼀次性传递多个参数(parallel命令可以,⽽且⽅式多种),只能寻求⼀些技巧来实现。cat | xargs -n2 bash -c 'wget "$1" -O "$2"'1.15 xargs的不⾜之处(此处必看)其实是xargs的限制和缺点,但因为通过"-i"选项⽅便演⽰,所以此处使⽤"-i"选项。注意,不是"-i"选项的缺陷。由于xargs -i传递数据时是在shell执⾏xargs命令的时候,根据 ,xargs后的命令如果有依赖于待传递数据的表达式,则⽆法正确执⾏。例如,⽆法通过xargs传递数值做正确的算术扩展:[root@xuexi logdir]# echo 1 | xargs -I "x" echo $((2*x))0⽆法将数据传递到命令替换中。[root@xuexi ~]# echo /etc/fstab | xargs -i `cat {}`
cat: {}: No such file or directory参考下图的shell命令⾏解析过程。这时要通过xargs正确实现⽬标,只能改变⽅法或寻找⼀些⼩技巧,例如:[root@xuexi ~]# echo 1 | xargs -i expr 2 * {} # 感谢楼下评论者提供的expr思路2[root@xuexi ~]# echo /etc/fstab | xargs -i cat $(echo {})
另外,xargs⽆法处理bash内置命令。例如:[root@xuexi ~]# echo /etc | xargs -i cd {}xargs: cd: No such file or directory
如果觉得⽂章不错,不妨给个打赏,写作不易,各位的⽀持,能激发和⿎励我更⼤的写作热情。谢谢!
发布者:admin,转转请注明出处:http://www.yc00.com/news/1688986190a191806.html
评论列表(0条)