linux管道命令xargs参数,【管道和xargs命令】-Linux/Unix/MAC OSX操作系统论坛-ZOL中关村在线...

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 diyersity: 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 ineach 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的输出是没有区别的。

注意:

[1] XXX | grep –i ‘hello’

[2] XXX | xargs grep –i ‘hello’

[1]的情况下,grep将通过管道读取XXXX的输出结果,并在该结果中搜索hello。

[2]的情况下,xargs将通过管道读取XXXX的输出结果,并将该结果作为grep的最后的FILE参数,和grep –i ‘hello’组合成完整的命令(如grep –i ‘hello’ stdio.h stdlib.h)后,执行该命令。grep从stdio.h stdlib.h文件中搜索hello。

两者对于管道的输出作不同的处理,前者是grep直接从stdin中读取管道数据,并搜索。后者是xargs(他的命令行选项为grep –i ‘hello’)直接从stdin中读取管道数据,并和grep –i ‘hello’组合,然后调用exec执行该命令。这种不同是体现在grep和xargs对读取管道数据后采取的不同处理,和管道本身的机制没有关系。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值