列出目录到grep的问题

H2O*_*aCl 4 command-line grep wc

grep在我的机器上似乎坏了。重新安装它没有帮助。重新启动没有帮助。前两行创建一个包含任意文本的文件,输入以 control-D 字符终止。

ls -1表示在一栏中列出。一个例子如下...

> cat > file0.txt
asdf
> cp file0.txt file1.txt
> ls -1
file0.txt
file1.txt
> ls -1 | grep f*
> 
Run Code Online (Sandbox Code Playgroud)

在遇到这个问题之前,我确实通过使用不匹配的引号调用 grep 犯了一个错误,但我不明白这个问题如何在重启后幸免于难。

无与伦比的报价示例...

ls -1 | grep 'file* | wc
Run Code Online (Sandbox Code Playgroud)

在这个例子中,目录列表通过管道传送到 grep,grep 通过管道传送到行、字和字节计数器程序wc

Sor*_*n A 14

grep f*在您的情况下,该表达式将grep file0.txt file1.txt被 shell扩展为。

显然file0.txt文件file1.txt中没有行。

我知道这不是你想要的,但它是如何工作的。

:~$ mkdir test
:~$ cd test/
:~/test$ touch f1
:~/test$ touch f2
:~/test$ set -x
:~/test$ ls | grep f* 
+ ls --color=auto
+ grep --color=auto f1 f2
Run Code Online (Sandbox Code Playgroud)

  • @H2ONaCl `grep` 永远不会从管道中读取数据。`grep` 只有在没有文件名参数传递给它时才会自动从它自己的标准输入中读取。由于 shell 将 `f*` 扩展为两个参数,`grep` 将其中一个参数视为正则表达式,另一个视为要读取的文件名。由于它有一个文件名参数,它*完全忽略*通过管道传输到它的数据。`ls` 不会打开任何一个文件,但它的输出会被丢弃;相比之下,`grep` * 确实* 打开了其中一个文件。所以这个答案是正确的。我添加了一个答案,详细说明为什么不使用 `ls` 的输出。 (7认同)
  • 他的回答是正确的,他解释说 bash shell 扩展和正则表达式是不同的东西,以及您错误使用 grep 的结果是什么。 (3认同)

Eli*_*gan 11

grep没有ls以任何方式使用输出。

当您grep f*在 shell 扩展f*为两个或多个参数的情况下运行时,grep将除一个参数之外的所有参数视为要打开和读取的文件名。grep从命名文件读取时,它从标准输入读取的默认行为不适用,因此它不会读取从另一个命令通过管道传输到它的数据。

您的grep程序没有损坏,您观察到的行为是正确的和预期的行为,这就是为什么重新安装grep和重新启动没有改变它的原因。详情如下。

grep f*没有通过f*grep的参数。

grep没看过文字f*正如Soren A 所说f*是一个 glob。球体由您的外壳特别处理。由于f*没有被引用,shell 将其扩展为当前目录中以f.开头的文件名。每个这样的名称都grep作为一个单独的参数传递给。(这种 shell 扩展被称为通配符、文件名扩展和路径名扩展。)

根据您的描述,恰好有两个文件与f*glob:file0.txtfile1.txt. 因为这些是在当前目录中其名称开头的只有两个文件f,传递到命令行参数grep运行grep f*完全一样的那些从运行传递给它grep file0.txt file1.txt。如果你要更多的这样的文件添加到目录中,然后grep f*会通过比两个文件名作为参数传递给更多的grep,但file0.txtfile1.txt仍然被列入其中。

您将ls输出通过管道传输到grep,但grep没有从管道中读取。

管道将一个命令的标准输出连接到另一个命令的标准输入。像cat许多其他命令,grep接受两种方式输入:

  1. 您可以将文件名作为命令行参数传递给它,它会从这些文件中读取。第一个非选项参数grep是模式,但后续的非选项参数被视为将从中获取输入的文件名。

    (您不是要尝试将多个模式传递给grep,但如果是,您可以使用该-e选项,其操作数始终被视为一个模式。)

  2. 您不能传递文件名参数,它将从它自己的标准输入中读取。在这种情况下,管道到 是有效的grep。只有在根本没有grep从标准输入读取的文件名参数的情况下

    这就是为什么可以使用它grep来搜索一个或多个文件,而不会阻塞并等待您在终端中输入输入。当您通过管道传输到 时grep,额外的输入没有意义,grep来自管道左侧的命令,而不是来自您的终端。grep仍然不使用它,这是一件好事。

    grep除了一个或多个命名文件之外,您不会试图导致读取标准输入,但如果是,您可以将-参数传递给它。)

因为当前目录中有两个文件名以 开头f,所以 globf*扩展为两个参数。第一个 ,file0.txt用作模式。第二个 ,file1.txt用于命名输入文件。因为grep给出了一个指定输入文件的参数,所以上述两种情况中的第一种适用(“您可以将文件名作为命令行参数传递给它”)。所以grep永远不要从标准输入读取,也永远不要使用ls.