在Bash中管,标准输入命令行参数 [英] Pipe, standard input and command line arguments in Bash

查看:134
本文介绍了在Bash中管,标准输入命令行参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑:

 命令1 |命令2

时的Command作为command2的命令行参数或作为标准输入输出命令2?

例如,

 猫test.sh | grep的嘿嘿

什么是它的等价形式,而不使用管?

我试过

 的grep嘿嘿$(猫test.sh)

和它似乎并不正确。


解决方案

 的grep嘿嘿< test.sh

输入重定向 - 仅适用于一个单一的文件,当然,而适用于任何数量的输入文件


考虑符号:

 的grep嘿嘿$(猫test.sh)
grep的嘿嘿`猫test.sh`

这些是在这种背景下当量;它是非常容易使用的 $(CMD)嵌套用途,如符号:

  X = $(目录名称$(目录名称$(其中GCC)))
X =`目录名\\目录名``\\\\\\其中GCC \\\\\\`\\``

(这使您可以在安装GCC的基本目录,在你想知道的情况下)。

的grep 例如,什么情况是,内容 test.sh 被读出并分割成白色-space分开的话,每个这样的话是作为参数传递给的grep 。由于的grep 嘻嘻(其中的grep ,当然,做的的看到双引号 - 并且不需要他们在这种情况下,作为一般规则,使用单引号,而不是双引号,尤其是在复杂的字符串像普通的前$ p经常使用shell元字符$ pssions)...就像我说的,的grep 后对待的话嘻嘻作为文件名,并尝试打开每个文件,通常是惨淡经营失败,因为不存在的文件。这就是为什么符号是在此上下文中适当


重新审视这个问题之后,还有更多的可以说 - 那尚未说

首先,许多Unix命令被设计为过滤器工作;他们阅读一些文件输入,改造它以某种方式,并将结果写入到标准输出。这些命令是专为命令管道中使用。例子包括:



  • 的grep

  • 的troff和亲戚

  • AWK(含警告)

  • SED

  • 排序

所有这些滤波器具有相同的特性:他们采取命令行选项来控制自己的行为,然后他们要么读指定为命令行参数的文件,或者,如果没有这样的论点,他们阅读的标准输入。有的(如排序),可以有选择来控制它们的输出去,而不是标准输出,但是这是比较少见的。

有一些纯粹的过滤器 - TR 就是这样 - 即严格标准输入读取和写入标准输出

其他命令具有不同的行为。雷蒙德提供的命令类型分类法中的的UNIX编程艺术。

有些命令生成标准输出文件名列表 - 两个经典的 LS 找到

有时候,你想从一个文件名发生器作为命令行参数应用滤镜的输出。有说是自动执行的程序 - 它是的xargs

经典,你可以使用:

 找到。 -name* [chyl。| xargs的grep的-n magic_name的/ dev / null的

这会生成文件的扩展名 .C .H '的完整列表, .Y .L (C源代码,头文件的Yacc和Lex文件)。由于名单是由的xargs 阅读,这会造成在用的grep -n magic_name的/ dev / null的命令行开始,每个字(用空格隔开)作为参数。<​​/ p>

在过去,UNIX文件名不包含空格。在Mac和Windows的影响力,这样的空间现在共到位。的GNU版本找到的xargs 具有互补选项来解决这个问题:

 找到。 -name'。* [chyl]'-print0 | xargs的-0的grep -n magic_name的/ dev / null的

-print0 选项表示终止打印文件名的NUL'\\ 0'(因为不能出现在一个(简单)文件中的唯一字符名字是'/'和NUL,显然,/可以在路径名称中出现)。相应的 -0 '告诉的xargs 寻找由NUL终止,而不是空格分隔名称的名称。

Consider:

command1 | command2

Is the output of command1 used as standard input of command2 or as command line arguments to command2?

For example,

cat test.sh | grep "hehe"

What is its equivalent form without using a pipe?

I tried

grep "hehe" $(cat test.sh)

and it seems not to be correct.

解决方案

grep "hehe" < test.sh

Input redirection - works for a single file only, of course, whereas cat works for any number of input files.


Consider the notations:

grep "hehe" $(cat test.sh)
grep "hehe" `cat test.sh`

These are equivalent in this context; it is much easier to use the '$(cmd)' notation in nested uses, such as:

x=$(dirname $(dirname $(which gcc)))
x=`dirname \`dirname \\\`which gcc\\\`\``

(This gives you the base directory in which GCC is installed, in case you are wondering.)

In the grep example, what happens is that the contents of test.sh is read and split into white-space separated words, and each such word is provided as an argument to grep. Since grep treats the words after "hehe" (where grep, of course, does not see the double quotes - and they are not needed in this case; as a general rule, use single quotes rather than double quotes, especially around complex strings like regular expressions which often use shell metacharacters)... As I was saying, grep treats the words after "hehe" as file names, and tries to open each file, usually failing dismally because the files do not exist. This is why the notation is not appropriate in this context.


After revisiting the question, there is more that could be said - that hasn't already been said.

First off, many Unix commands are designed to work as 'filters'; they read input from some files, transform it in some way, and write the result onto standard output. Such commands are designed for use within command pipelines. Examples include:

  • cat
  • grep
  • troff and relatives
  • awk (with caveats)
  • sed
  • sort

All these filters have the same general behaviour: they take command line options to control their behaviour, and then they either read the files specified as command line arguments or, if there are no such arguments, they read their standard input. Some (like sort) can have options to control where their output goes instead of standard output, but that is relatively uncommon.

There are a few pure filters - tr is one such - that strictly read standard input and write to standard output.

Other commands have different behaviours. Eric Raymond provides a taxonomy for command types in "The Art of UNIX Programming".

Some commands generate lists of file names on standard output - the two classics are ls and find.

Sometimes, you want to apply the output from a file name generator as command line arguments for a filter. There's a program that does that automatically - it is xargs.

Classically, you would use:

find . -name '*.[chyl]' | xargs grep -n magic_name /dev/null

This would generate a complete list of files with the extensions '.c', '.h', '.y' and '.l' (C source, headers, Yacc and Lex files). As the list is read by xargs, it would create command lines with grep -n magic_name /dev/null at the start and each word (separated by white space) as an argument.

In the old days, Unix file names didn't include spaces. Under the influence of Mac and Windows, such spaces are now common-place. The GNU versions of find and xargs have complementary options to deal with this problem:

find . -name '*.[chyl]' -print0 | xargs -0 grep -n magic_name /dev/null

The '-print0' option means "print file names terminated by a NUL '\0'" (because the only characters that cannot appear in a (simple) file name are '/' and NUL, and obviously, '/' can appear in path names). The corresponding '-0' tells xargs to look for names terminated by NUL instead of space separated names.

这篇关于在Bash中管,标准输入命令行参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆