xargs命令少为人知的细节
发布于 2010-04-29 11:20 阅读:61,774 评论:0 标签: xargs

    与xargs命令最初相识是在发现一个磁盘满了,具体是在/var/spool/clientmqueue,主要原因是系统中有用户开启了crontab,而crontab中执行的程序有输出内容,输出内容会以邮件形式发给cron的用户,而sendmail没有启动所以就产生了这些文件。关于更详细的原理,可以参考我之前的文章:crontab命令的使用介绍及我的体会

    仅仅解决出现多文件的方法比较简单,在命令后加上“> /dev/null 2>&1”即可,表示程序员输出和运行错误都放到黑洞里面去,这样就不会产生文件了。

    如果是要解决删除多文件的问题,则进入这个文件夹,执行“ls | xargs rm -f ”即可。xargs可以从管道中循环读取文件,一次一次的把信息输送给后面的“rm -f”。

    请注意以上措辞:“一次一次的”,那么这个一次一次,是指“一个一个”还是“一批一批”呢?

    很杯具,当时不求甚解,未能深入学习xargs,误解为“一个一个”。

    最近在写一个程序时,需要处理一个文件中的行数据。平时都是使用php的fopen再fgets解决问题,但这次懒得套用这一套了,于是想使用管道把数据传送给php脚本。

    而php脚本也利用$argv这个数组来获取命令行输入的参数,那么很简单的,获取$argv[1],就可以了。如“php a.php b”,$argv[0]为文件名a.php,$argv[1]就是后面的参数b了。于是想当然的:cat uid.txt | xargs php a.php 。

    最终发现,uid.txt中有近4千行的数据,但是只处理了4行。那么,既然出现问题就边解决边学习吧!

    使用:cat uid.txt | xargs echo > file.out

    发现 file.out文件果然就是四行,但是每行都很长。。。。。

    如下,uid.txt内容为:(“......”表示很多行)

以下是引用片段:
1234567890
......
2234567890
......
3234567890
......
4234567890
......

    那么file.out的结果为:

以下是引用片段:
第一行:1234567890 ......
第二行:2234567890 ......
第三行:3234567890 ......
第四行:4234567890 ......

    所以,程序处理每一行的第一个了,剩下的全部被忽略。而我期望的结果是xargs每次给我一行。

    那么寻求man的帮助吧:

以下是引用片段:

       --max-chars=max-chars, -s max-chars
              Use at most max-chars characters per command line, including the command and initial-arguments and  the
              terminating nulls at the ends of the argument strings.  The default is 131072 characters, not including
              the size of the environment variables (which are provided for separately so that it doesn’t  matter  if
              your  environment variables take up more than 131072 bytes).  The operating system places limits on the
              values that you can usefully specify, and if you exceed these a warning  message  is  printed  and  the
              value actually used is set to the appropriate upper or lower limit. 

       --max-args=max-args, -n max-args
              Use  at  most  max-args  arguments per command line.  Fewer than max-args arguments will be used if the
              size (see the -s option) is exceeded, unless the -x option is given, in which case xargs will exit.

    首先看-s参数,它提示说每次的输出不能超过131072 bytes,从结果上看上去它每次都往最大的值释放数据。再看-n参数,提示我们可以使用这个参数指定每次从源文件中取几行数据,那么OK,搞定了!如下:cat uid.txt | xargs -n 1 php a.php。问题解决。

    更进一步的:

    1:其实每个系统对于参数列表的大小都有限制。比如ARG_MAX一般至少定义为4096 bytes。如果超过了ARG_MAX,将产生shell错误:Argument list too lang,这个问题可以用上面说的xargs命令解决问题。

    2:xargs的-s参数,根据实战的结果,貌似会在指定的值和真实数据中取得平衡,不会只依据-s指定的大小活生生的把源数据的一行撕裂成两行。