zoukankan      html  css  js  c++  java
  • xargs命令_Linux xargs命令:一个给其他命令传递参数的过滤器

    本文要为大家介绍的命令是 xargs,我们把它称为护花使者,因为它总是乐于协助其他的命令来完成一些事情。下面一起来看看它是如何护花的。

    xargs 是 execute arguments 的缩写,它的作用是从标准输入中读取内容,并将此内容传递给它要协助的命令,并作为那个命令的参数来执行。

    坊间有一种说法,将 xargs 解读为乘号(x)和参数(args)的合体,很形象地表达了 xargs 的作用所在。

    好了,我们一起来见识一下 xargs 的护花本领吧:

    我们用ls命令列出当前路径下的文件, 包括3个文件

    [roc@roclinux ~]$ ls
    china.txt  usa.txt japan.txt
    

    我们通过xargs + ls的方式列出my.txt文件和your.txt文件

    [roc@roclinux ~]$ echo "china.txt usa.txt" | xargs ls
    china.txt usa.txt
    

    可以很清晰地看到,xargs 将 echo 的输出作为自己的标准输入,并且将其传递给了 ls 命令,作为 ls 命令的参数来执行。
    xargs 和管道不得不说的故事
    为了能够为大家解释清楚 xargs 和管道的关系,我们这次选用了更加典型的 cat 命令来为大家举例。

    为什么选择 cat 命令呢?众所周知,cat 命令可以接收文件名作为参数,执行后会显示出文件的内容。但是 cat 命令不能直接从标准输入接收参数,正如下面的例子:

    cat后面直接指定china.txt参数, 可以展示china.txt文件的内容

    [roc@roclinux ~]$ cat china.txt
    hello beijing
    

    我们尝试通过标准输入把参数传给cat, 结果却只是显示了文件名而已

    [roc@roclinux ~]$ echo china.txt | cat
    china.txt
    

    从上面的例子中,我们可以得出下面的结论:
    管道可以实现:将前面的标准输出作为后面的“标准输入”。
    管道无法实现:将前面的标准输出作为后面的“命令参数”。

    这个时候,就要有请 xargs 这位护花使者了。xargs 所擅长的正是“将标准输入作为其指定命令的参数”。说着有些拗口,但我相信大家懂的。

    xargs果然不负众望, 协助cat完成了使命

    [roc@roclinux ~]$ echo china.txt | xargs cat
    hello beijing
    

    我们知道,xargs 会将前一个命令的标准输出转换成命令参数,但很多人可能不知道的是,xargs 的标准输入中出现的“换行符、空格、制表符”都将被空格取代。下面来看一个带有换行符的例子:

    我们准备好了带有换行的标准输入

    [roc@roclinux ~]$ echo -e "china.txt
    japan.txt"
    china.txt
    japan.txt
    

    可见, 换行符和空格的作用一样

    [roc@roclinux ~]$ echo -e "china.txt
    japan.txt" | xargs cat
    hello beijing
    hello tokyo
    

    上面的例子是一个比较简单的场景,我们有时还会遇到更棘手的情况,一起来看一看。

    当命令参数中包含了空格时,情况就会复杂很多,一起来看一个示例。

    我们创建了3个日志文件, 且故意让文件名称中都含有空格

    [roc@roclinux ~]$ for((i=0;i<3;i++)); do touch "test ${i}.log";done
    

    我们列出创建的文件

    test 0.log
    test 1.log
    test 2.log
    

    我们来运行xargs命令, 发现报错了

    [roc@roclinux ~]$  find . -name '*.log' -print | xargs rm
    rm: cannot remove ‘./test’: No such file or directory
    rm: cannot remove ‘1.log’: No such file or directory
    rm: cannot remove ‘./test’: No such file or directory
    rm: cannot remove ‘0.log’: No such file or directory
    rm: cannot remove ‘./test’: No such file or directory
    rm: cannot remove ‘2.log’: No such file or directory
    

    我们在当前目录中创建了 3 个文件,文件名中间都含有空格。但当 find 命令获取到的文件名经过 xargs 传送给 rm 命令时,文件“./test 1.log”就变成了“./test”和“1.log”两个文件了。即原本 3 个文件名刹那间就变成了 6 个文件名,而这 6 个文件其实并不存在,从而引发了错误。

    这个错误的根源就在于 xargs 默认的分隔符是空格,如果我们能将 xargs 的分隔符改成其他符号,问题就迎刃而解了!

    xargs 提供了-0选项,允许将 NULL 作为分隔符,而 find 命令也心有灵犀地提供了对应的选项来产生以 NULL 字符作为分隔符的输出。

    find 命令提供的对应方法是 -print0 选项,在文件名之后输出 NULL,而不像 -print 选项那样输出换行符(换行符会被 xargs 替换成空格)。

    正如我们所期待的,命令果然正常执行了,完美!

    [roc@roclinux ~]$ find . -name '*.log' -print0 | xargs -0 rm -f
    

    对了,要补充一点,xargs 的-0选项不仅可以将分隔符从默认的空格变成 NULL,还会将单引号、双引号、反斜线等统统默认为是普通字符。所以说,-0选项特别适合处理命令参数中含有引号、空格、反斜线的情况。

    如果你是一位 GEEK,希望掌握得更深入,那么我们就再补充一个知识点。除了可以使用-0选项外,其实还可以使用-d选项来指定任何一个符号作为分隔符。只是我们要格外慎重,避免我们所设定的那个分隔符恰好是我们命令参数中所包含的字符,那就会导致非预期的结果了。
    让护花使者听我们的话
    如果在前一个命令的标准输出中,会有一些参数是你不希望或者不确定是否要传送给后面命令的,这个时候我们就希望 xargs 在传送参数前和我们确认一下。而-p选项恰好可以实现这个愿望,我们可以输入 y 或者 n 来选择是否要执行当前命令:

    [roc@roclinux ~]$ find . -type f |xargs -p rm -f
    rm -f ./china.txt ./usa.txt ./japan.txt ?...n
    

    上面的命令中,我们输入了“n”,也就是不希望删除这三个文件。不过,这样的确认粒度太粗,我们希望的是更精细地确认,来试试-n选项吧:

    [roc@roclinux 20160408]$ find . -type f |xargs -p -n 1 rm -f
    rm -f ./china.txt ?...n
    rm -f ./usa.txt ?...y
    rm -f ./japan.txt ?...n
    

    使用-n选项,可以让 xargs 每次只处理 1 个参数,这样做的好处是避免一次性删除过多文件,万一误删了不该删除的文件,那麻烦就大了。
    遇到就停止
    xargs 已经足够优秀了,可以帮助我们处理各种各样的问题。但我们对 xargs 还有更加苛刻的要求,那就是当碰到某个特定的命令参数时,要求 xargs 立即终止并退出。

    这个效果,我们可以使用-E选项来实现。

    比如,我们正在处理一份日志文件 country.list 中的内容,将日志文件中的字符以空行作为分隔符依次 echo 出来,一旦遇到 korea 便终止退出:

    [roc@roclinux ~]$ echo "china usa korea japan" > country.list
     
    [roc@roclinux ~]$ cat country.list
    china usa korea japan
     
    [roc@roclinux ~]$ cat country.list | xargs -E 'korea' echo
    china usa
    

    可以看到当处理到 korea 的时候,xargs 机警地发现了状况,于是,按照我们的要求,立即终止并退出了。好乖的 xargs 啊!
    你可能一生都不会遇到的参数过长报错
    可能很多运维工程师都没有遇到过“Argument list too long”这样的报错。但要想成为一名资深的运维工程师,了解它的原因和解决方法还是很有必要的。

    我们来模拟一个这样的场景,新建 10 万个日志文件,并且尝试用 rm 命令一次性删除:

    [roc@roclinux ~]$ for((i=0;i<100000;i++)); do touch test${i}.log;done
     
    [roc@roclinux ~]$ rm $(find . -type f -name '*.log')
    -bash: /bin/rm: Argument list too long
    

    出现了“Argument list too long”报错,这说明 rm 可接受的参数长度达到了极限。这其实并非 rm 的错,而是系统限制了参数的长度。通过下面的命令可以查看到系统的参数长度限制值:

    [roc@roclinux ~]$ getconf ARG_MAX
    2621440
    

    如果真的遇到了参数过长的问题,我们的应对方法其实有很多种,比如把文件手工分组以缩短参数的长度,但是这个方法并不优雅,而且费时费力。最优雅的方法当然就是借助 xargs 啦:

    [roc@roclinux ~]$ find . -name '*.log' -print | xargs rm
    

    借助 xargs,并利用管道的特性,find 命令将输出的内容分段传给 rm 命令,而不是一股脑儿地塞过去。这样一来,rm 命令可以先处理最先获取的一部分文件,然后再处理下一批,并一直继续下去,直到全部删除为止。

    好了,xargs 这位护花使者是不是既聪明又听话呢,在运维过程中,尝试使用起来吧,你会事半功倍的!

  • 相关阅读:
    第二十一章流 1流的操作 简单
    第二十章友元类与嵌套类 1友元类 简单
    第十九章 19 利用私有继承来实现代码重用 简单
    第二十章友元类与嵌套类 2嵌套类 简单
    第十九章 8链表类Node 简单
    第二十一章流 3用cin输入 简单
    第十九章 10 图书 药品管理系统 简单
    第十九章 11图书 药品管理系统 简单
    第二十一章流 4文件的输入和输出 简单
    第十九章 12 什么时候使用私有继承,什么时候使用包含 简单
  • 原文地址:https://www.cnblogs.com/nul1/p/12123209.html
Copyright © 2011-2022 走看看