$(ls *.txt) 有什么作用?

Ban*_*ana 6 command-line bash

在 unix 终端中,如果我这样做:

egrep "Stuff" $(ls *.txt)
Run Code Online (Sandbox Code Playgroud)

结果是显而易见的。但是有什么用

$(ls *.txt)自己做?我看到我可以通过以下方式复制效果

egrep "Stuff" *.txt
Run Code Online (Sandbox Code Playgroud)

那么什么是$(ls *.txt)

Joh*_*024 28

“做$(ls *.txt)什么”

简答

$(ls *.txt)收集文件名列表,然后对它们进行处理。千万不能使用。

更长的答案

  • ls用于人类可读的输出。正如 ls 的一位维护者在回答为什么不提供选项时写道ls--null

    如果我们要这样做,那么这就是我们将使用的接口。然而, ls它确实是一种供人类直接消费的工具,在这种情况下,进一步处理就没那么有用了。对于进一步的处理,find(1)更适合。[强调]

    换句话说,ls除了向人类显示之外,不支持将用于任何其他用途。 ls例如,维护者最近将默认输出格式更改为他们认为更人性化的格式而没有警告。因此,听从他们的建议:如果你打算做文件名的进一步处理,采用find替代ls

  • $(...)是命令替换。使用命令替换的结果之一是删除了尾随的换行符。如果列表中的最后一个文件名恰好包含尾随换行符,它们将被删除。

  • 由于$(...)不是双引号,它产生的文本将受制于:

    • 分词

    • 路径名扩展

    这两者的结果是进一步修改文件名。

  • 更何况问题与文件名开头-,因为失踪--(用于lsegrep作为Ubuntu的egrep是GNU的实施也会接受后非选项参数选项,除非POSIXLY_CORRECT是在环境中)。

  • 此外,如果这些txt文件中的任何一个是directory类型,ls则会列出它们的内容而不是它们本身。

  • 如果没有txt文件,输出ls将为空(尽管您会看到有关丢失*.txt文件的错误)并且egrep不会收到文件参数,它将在其标准输入中查找Stuff(并且似乎挂起)。

例子

让我们Stuff在我们的目录中创建 4 个文件:

$ echo Stuff | tee file1 file2 'a b c.txt' 'f* .txt'
Stuff
$ ls -Q
"a b c.txt"  "file1"  "file2"  "f* .txt"
Run Code Online (Sandbox Code Playgroud)

现在,让我们运行 egrep 命令:

$ egrep "Stuff" $(ls *.txt)
grep: a: No such file or directory
grep: b: No such file or directory
grep: c.txt: No such file or directory
file1:Stuff
file2:Stuff
f* .txt:Stuff
grep: .txt: No such file or directory
Run Code Online (Sandbox Code Playgroud)

观察到我们收到 4 条关于不存在文件的错误消息。这是由于分造成的。结果也与两个文件表演比赛,file1file2这不应该被搜查,因为他们不结束.txt。这是因为 _pathname 扩展`。

正确编写的命令会产生两个成功的匹配并且没有错误:

$ egrep -- "Stuff" *.txt
a b c.txt:Stuff
f* .txt:Stuff
Run Code Online (Sandbox Code Playgroud)

推荐方案

用:

egrep -- "Stuff" *.txt
Run Code Online (Sandbox Code Playgroud)

或 POSIXly:

grep -E -- "Stuff" *.txt
Run Code Online (Sandbox Code Playgroud)

或者:

grep -E -e Stuff -- *.txt
Run Code Online (Sandbox Code Playgroud)

这将适用于任何文件名,并且没有该ls方法的任何限制。


wal*_*tor 6

$( )运行命令ls *.txt和返回STDOUT命令。

这种特殊用法是至少在三个层面上的新手编程错误:

  1. egrep 'Stuff' *.txt 像你说的那样工作,除了命名为类似的文件 A File.txt
  2. ls输出用于程序输入是不明智的。查看原因
  3. $( ls *.txt)错误处理带有空格和其他有趣字符的文件名。find . -maxdepth 1 -type f -iname '*.txt' -print0 | xargs -0 egrep 'Stuff'是一种更防弹的方式。

响应 @8bittree 的 shell glob 扩展/混淆的一个人为示例是:

$ /bin/ls -l -b
total 36
-rw------- 1 w3 walt 2 Aug 11 13:41 A\ \\012\ File.txt
-rw------- 1 w3 walt 2 Aug 11 13:42 A\ \n\ File.txt
-rw------- 1 w3 walt 2 Aug 11 13:40 A\ File.txt

$ grep "STUFF" $(ls *.txt)
grep: A: No such file or directory
grep: \012: No such file or directory
grep: File.txt: No such file or directory
grep: A: No such file or directory
grep: File.txt: No such file or directory
grep: A: No such file or directory
grep: File.txt: No such file or directory

$ find . -maxdepth 1 -type f -iname '*.txt' -print0 | xargs -0 egrep 'Stuff'

$ find . -maxdepth 1 -type f -iname '*.txt' -print0 | xargs -0 egrep '1'
./A File.txt:1
Run Code Online (Sandbox Code Playgroud)