为什么 ls -R(向下递归)不适用于正则表达式

why the ls -R (recursing down) doesn't work with regular expression

在我的例子中,目录树如下

[peter@CentOS6 a]$ tree  
.  
├── 2.txt  
└── b  
    └── 1.txt

1 directory, 2 files

为什么下面两条命令只能得到2.txt?

[peter@CentOS6 a]$ ls -R *.txt
2.txt
[peter@CentOS6 a]$ ls -R | grep *.txt
2.txt

您可以使用如下查找方式列出当前目录和子目录中所有匹配的文件

find . -name "*.txt"

在这两种情况下,您的 shell 在参数命中命令之前将 *.txt 扩展为 2.txt。所以,你实际上是运行

ls -R 2.txt
ls -R | grep 2.txt

您不能告诉 ls 查找文件模式 - 这就是 find 的用途。在第二种情况下,您应该引用您的表达式并使用适当的正则表达式:

ls -R | grep '\.txt'

不清楚您问的 "why" 是指 "explain the output" 还是 "how should it be done"。 Steephen已经回答了后者,这是对前者的回答。

原因叫做"shell expansion"。当您在命令行中键入 *.txt 时,程序不会将其作为参数获取,而是 shell 展开它然后传递结果。

*.txt 扩展为 "all files in the current directory with arbitrarily many symbols in the beginning, ending with '.txt' and not starting with '.'".

这意味着当你输入“ls -R *.txt”时,实际执行的命令是“ls -R 2.txt”;当您执行“ls -R | grep *.txt”时,它实际上执行“ls -R | grep 2.txt”。

这就是 Steephen 在提供的答案中将通配符用引号引起来的确切原因。有必要停止这种扩张。事实上,您也可以使用单引号或在任何特殊字符前放置一个斜线。因此,以下任何一项都有效:

find . -name "*.txt"

find . -name '*.txt'

find . -name \*.txt

另一个还没有人提到的问题是,除了 shell 在 grep 看到它之前拦截 * 之外,shell 对待 * 不同于 grep.

shell 使用文件 globbing,* 表示 "any number of characters"。

grep使用正则表达式,*表示"any number of the preceding item".

你需要做的是

ls -R | grep .\*\.txt

哪个会

  • 转义 * 这样你的 shell 就不会拦截它
  • 按照grep期望的方式正确格式化正则表达式
  • 正确转义 .txt 中的 . 以确保您有文件扩展名