http://blog.csdn.net/yongan1006/article/details/8134581
一直弄不懂,管道不就是把前一个命令的结果作为参数给下一个命令吗,那在 | 后面加不加xargs有什么区别
NewUserFF 写道:
懒蜗牛Gentoo 写道:
管道是实现“将前面的标准输出作为后面的标准输入”
xargs是实现“将标准输入作为命令的参数”
你可以试试运行:
代码:
echo "--help"|cat
echo "--help"|xargs cat
看看结果的不同。
试过了,依然不是很确定的明白到底是什么意思,自己再探索一下看看把
如果你直接在命令行输入cat而不输入其余的任何东西,这时候的cat会等待标准输入,因此你这时候可以
通过键盘输入并按回车来让cat读取输入,cat会原样返回。而如果你输入--help,那么cat程序会在标准输出上
打印自己的帮助文档。也就是说,管道符 | 所传递给程序的不是你简单地在程序名后面输入的参数,它们会被
程序内部的读取功能如scanf和gets等接收,而xargs则是将内容作为普通的参数传递给程序,相当于你手写了
cat --help
来自:http://forum.ubuntu.org.cn/viewtopic.php?t=354669
补充解释:
在一个目录中有如下三个文件
a.c b.c c.c
find . / -print命令会打印出三个文件名
find . / -print | grep a.c 只会打印出a.c这个文件
如果只输入命令grep a.c
那么你在键盘中只输入a.c字符串时,a.c会被打印两次,否则只打印你输入的字符
如果要找三个文件中,那个文件包括有hello字符
find ./ -print | xargs grep hello
总结:管道符后不加xargs相当于先将xargs后面的命令回车执行一下再从键盘里输入
管道符前面命令执行的结果内容
加上xargs 相当于直接从键盘输入管道符前面命令执行的结果内容再回车
再总结一下,就是回车的先后顺序不太一样。
http://blog.csdn.net/peteryxk/article/details/1622491 (由于不能转载,只留下)
管道和xargs命令
1,stdin,stdout,stderr
对于新生成的任何进程来讲,都可以使用stdin,stdout,stderr这些文件指针来访问标准输入,标准输出,错误文件。他们的类型都是FILE *,属于c运行库的类型。而内核则使用文件描述符来代表文件。STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO分别被定义为0,1,2。
Dup2( srcfd , destfd )的作用为将srcfd文件描述符复制一份,并且让destfd代表复制后的文件描述符。这样srcfd,destfd指向共同的file table entry,并拥有共同的inode。调用该函数时,destfd除了可以是普通的文件描述符之外,还可以是STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO的任意一个。这就位管道命令提供了很好的支持。
注:调用dup2时,如果destfd已经是一个有效的文件描述符,那么将首先关闭destfd(调用close函数)。
2,fork
fork函数可以生成子进程,并且子进程共享父进程的所有的文件描述符,数据,heap,stack。Child其实是parent的一份clone。事实上linux就是利用clone实现的fork。
把fork和dup2,pipe结合起来,就可以实现shell中支持的管道|了。
[1] 父进程首先调用pipe,返回fd0(用来从管道读数据),fd1(用来象管道写数据)
[2] 父进程调用fork生成子进程,此时子进程也共享到了父进程的fd0,fd1
[3] 子进程调用dup2( fd0 , STDIN_FILENO),这样就导致了子进程从stdin读取数据时,实际是从管道读取数据
[4] 子进程调用exec系列函数,执行相应的程序
[5] 父进程通过fd1向管道写数据
[6] 子进程通过stdin读取父进程向管道写入的数据。
其实,这就是shell执行管道的基本流程。
3,|
一般的控制台程序都是从stdin读取参数或需要处理的数据,并把结果输出到stdout中。而unix的哲学是:
[1] Rule of Modularity: Write simple parts connected by clean interfaces
[2] Rule of Composition: Design programs to be connected to other programs
[3] Rule of Clarity: Clarity is better than cleverness
[4] Rule of Simplicity: Design for simplicity; add complexity only where you must
[5] Rule of Transparency: Design for visibility to make inspection and debugging easier
[6] Rule of Robustness: Robustness is the child of transparency and simplicity
[7] Rule of Least Surprise: In interface design, always do the least surprising thing
[8] Rule of Repair: When you must fail, fail noisily and as soon as possible
[9] Rule of Economy: Programmer time is expensive; conserve it in preference to machine time
[10] Rule of Generation: Avoid hand-hacking; write programs to write programs when you can
[11] Rule of Representation: Use smart data so program logic can be stupid and robust
[12] Rule of Separation: Separate policy from mechanism; separate interfaces from engines
[13] Rule of Optimization: Prototype before polishing. Get it working before you optimize it
[14] Rule of Diversity: Distrust all claims for “one true way”
[15] Rule of Extensibility: Design for the future, because it will be here sooner than you think
基于这些哲学,就导致了unix系统中有很多小的工具,每个工具的功能都很单一,并且这些工具可以任意组合,完成复杂的功能。比如find,grep,awk,xargs等等的组合。
这些功能组合是通过管道|来完成的,即前一个程序的输出,作为下一个程序的输入。
我们看看grep的命令行参数:
Usage: grep [OPTION]... PATTERN [FILE] ...
Search for PATTERN in each FILE or standard input.
Example: grep -i 'hello world' menu.h main.c
我们可以看到,grep可以从多个文件中搜索字符串,并且也可以从stdin读取字符串并搜索。上例中,就是从menu.h main.c中搜索hello world。如果输入grep –i ‘hello’,并回车,然后grep将等待用户输入一行数据,并在该行数据中搜索hello,如果找到的话,就会输出该字符串。
$grep –i ‘hello’
Abcdefg
Hi hello
Hi hello
Stop
^D
$
其中蓝色的字符为用户输入的字符,红色的为grep找到匹配的字符串后,输出的字符。
我们可以猜到grep的实现,如果命令行的最后有一个文件名,或多个文件名,或路径的话,将从这些文件中读取内容,并匹配regex。否则的话,将从stdin读取数据,并匹配regex。
联系到上面所讲的pipe,fork,dup2函数,我们可以看到,这就是shell的基本执行过程。需要注意的是,grep必须支持从stdin读取数据,否则管道就不能够实现了。当然,想支持管道操作的程序必须遵守这个规则。
4,Xargs
假设有这样一个需求,我们需要从整个文件系统中搜索字符串hello,我们写了如下的shell:
$grep –i ‘hello’ /*/*
这将导致命令行参数太多。而每个系统对于参数列表的大小都有限制。比如ARG_MAX一般至少定义为4096 bytes。如果超过了ARG_MAX,将产生shell错误:
Argument list too lang
为了避免这个问题可以使用xargs命令。他的格式为:
xargs [opt] [ command [initial-arguments] ]
其中opt是xargs本身的命令行参数。
他的作用为,build and execute command lines from standard input。他从stdin读取由空格分割的字符串(假设为arg0,arg1,… argN),并执行command [initial-arguments] arg0 arg1 …argN,如果参数太多的话,xargs保证参数大小在不超过系统限制的ARG_MAX bytes大小的前提下,一次或多次执行command [initial-arguments]命令。比如执行了如下命令:
$find / -name ‘*.h’ | xargs grep –i ‘stdin’ | less
假设执行两次,第一次为grep –i ‘stdin’ a1.h a2.h … a3000.h | less
第二次为grep –i ‘stdin’ a3001.h a3002.h … a4000.h | less
该命令的实际执行情况为:(推测)
Shell执行find,xargs和less程序。xargs顺序执行了两次grep程序。
xargs从find的结果读取数据是很普通的,不需要额外的解释。
xargs同less的数据传递看起来有些麻烦,其实也挺简单的。xargs从stdin读取管道的数据,并按照ARG_MAX为界限进行分割,执行fork和execv(“grep”)一次或多次就可以了。因为grep使用普通的printf来输出结果,而这样的结果正好作为less的输入。因为xargs和grep虽然存在父子关系,但是他们的stdout是同一个stdout。对于less程序来讲,grep的输出和xargs的输出是没有区别的。