zoukankan      html  css  js  c++  java
  • 除了管道和重定向,还有命令行参数

    除了管道和重定向,还有命令行参数

    与本文无关,最近的照片,[http://www.douban.com/photos/album/106885669/],黄昏的月亮。


    管道和重定向,在Unix Shell Script入门教程里都要提到。在稍微深入一点的dos/windows批处理教程里也要提到。管道,一般在用前一个进程产生的输出,作为后一个进程的输入;重定向,一般用在把输出由控制台转到文件,或者用文件替代控制台输入。管道和重定向满足了进程的输入和输出的转向。

    输入和输出,似乎本来就是进程跑起来以后唯一与外界的联系。根据与外界的联系判定那是个什么东西,而不是根据它的内心,这据说是萨特的观点,小资们不可不知。

    不过,输入和输出,并非进程与外界唯一的联系。除了输入以外,命令行参数,也是设定进程行为的重要依据。在这一点上,如果把进程当成一个对象,命令行参数有点像构造函数的参数,虽然跑起来以后就跟它无关了。而且,unix程序一般地,只有命令行参数才是命令,影响进程的行为,而以后从标准输入读进来的所有东西,都只是数据而已,是被进程处理的东西,对进程本身没有影响。

    shell (像python一样),是一种不错的粘合剂,它能组装一系的进程,让它们协同工作。管道和重定向,能让它们完成生产者-消费者这样的组合。

    不过,如果我们需要一个进程的输出,不是作为另一个进程的输入,而是作为它的命令行参数呢?

    下面的写法,
    a | b
    完成的,是把a的输出作为b的输入。

    而如果我们希望下面这样,如何表达?
     b -para <此处是a的输出>

    有不止一种方法。

    1. backtick

    backtick,就是"`"。这不是单引号,而是键盘左上角,波浪线 (~)下面的那个小点,像个反向的单引号。

    它的作用是,把括起来的命令执行了,并用执行结果中的每一行去替换命令所在的位置。

    ls `echo -l`

    相当于

    ls -l

    我们把其中的一段拿出来单独执行一下。

    1 $ echo -l
    2 -l

    可见,"echo -l"的结果,就是"-l"。其中的""中为了避免echo把"-l"当成自己
    的参数。

    而"-l"替换了"ls `echo -l`"中反引号括起来的部分,所以"ls `echo -l`"就
    变成了"ls -l"。

    再举个例子。

    1 $ grep -w main `find . *c`
    2 ./samples/hidraw/hid-example.c:int main(int argc, char **argv)
    3 ./samples/trace_events/Makefile:# have that tracer file in its main search path. This is because
    4 ./Makefile:# $(vmlinux-main). Most are built-in.o files from top-level directories
    5 ./Makefile:#   +--< $(vmlinux-main)
    6 ./Makefile:vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
    7 ./Makefile:vmlinux-all  := $(vmlinux-init) $(vmlinux-main)
    8 ...

    这条命令的作用是,先执行 "find . *c",找到当前目录下所有子目录中的 c文件,然后对每个符合条件的文件执行 "grep -w main"。

    命令"grep -w main `find . *c`"中,`find . *c`部分将被替换为很多个匹配的文件名,然后每个文件名都作为 "grep -w main"的命令行参数,类似于:

    grep -w main a.c
    grep -w main b.c
    grep -w main c.c

    这样。

    2. $(cmd)

    backtick倒是挺方便,不过很多同学反映,"`"这个符号太丑陋了。最丑陋的特性之一就是,它跟单引号"'"长得太过地相似了。像我这样认人脸有困难的,本来就希望大家服饰发型更多样化一些,所以你能够理解我现在看到女演员们长得都越来越像,该是多么大的困惑。我指的不光是韩国的,小锥子脸大眼睛面孔白而无表情。backtick也存在这样的问题,跟别人像,本来就是毛病。

    所以有别的写法,比如这样:

    grep -w main $(find . *c)

    这样的效果跟backtick是一样的。一样一样的。区别呢?多少也有一些。比如 $(cmd) 这样写法是可以嵌套的。

    3. xargs

    不过上述这些需要"代换"的,似乎有些程序员理解起来有困难?后来出现了一个命令,xargs,专门用来做这件事。

    find . *c | xargs grep -w main {}

    请注意到find和grep的顺序换了。find的输出结果,由xargs转给grep作为命令行参数。事实上,是xargs调用了grep,管道的末端不是grep,而是xargs。这不同于管道的末端是grep,如果是这样,就成了find的输出作为grep的输入,是管道应用的更一般的情况。args把管道的输出转向了grep的命令行参数,而不是作为grep的输入。

    "{}"在这里,将被find的输出替代。如果命令行参数的位置不重要,或者在最末端,那么还可以把"{}"省略掉,效果是一样的。像这样:

    find . *c | xargs grep -w main

    4. -exec

    似乎有了xargs以后,还是有些程序员觉得不够简单?又有些命令自带了"-exec"参数,意谓:如果匹配了,就把那些输出作为"-exec后面的进程的命令行参数"。话说,有些事情由于它的领域模型就那么复杂,是不太可能因为表达方式而变得简单的。

    以下命令,效果是一样的:
    find . *c -exec grep -w main {} -nH ;

    行尾的";",是为了标识"-exec"部分结束,其中的""是因为";"是个特殊字符。grep需要"-nH"参数,是因为不然输出的匹配行里没有文件名和行号。grep在此前的几个命令里用的是别名,这里是真正的grep本身。

    5. 总结

    以下几个命令等价:
    $ cat `which 20.sh`
    $ cat ${which 20.sh}
    $ which 20.sh | xargs cat

    cat不支持"-exec"参数,那是find这样的复杂命令的特色,因此以上总结中未包括。

    ----------

    本文的命令在 emacs eshell 不好使,因为 eshell 对管道支持不充分,shell-mode则没有问题。

    --------------------


    博客会手工同步到以下地址:


    [http://giftdotyoung.blogspot.com]


    [http://blog.csdn.net/younggift]

  • 相关阅读:
    利用.Net的CLR和BCL实现函数IsNumeric
    30岁前挣到10万年薪 五位年轻人的高薪秘诀
    三级关链菜单通用版
    对Session和Cookie的区分与理解
    转贴:C#排序算法大全
    无效的 CurrentPageIndex 值.它必须大于等于 0 且小于 PageCount!的问题
    ASP.NET中“检测到有潜在危险的表单值”的解决方法
    如何让网页版面更适合浏览者呢?这里有技巧
    十二星座情侣恋爱积分
    asp.net 三种基本的参数传递方法(web forms)
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3201265.html
Copyright © 2011-2022 走看看