我决定读一本关于 Linux/Unix 的书。我已经读到了一章,他们试图解释如何将命令的输出作为扩展传递到 shell。
以下命令
file $(ls /usr/bin/* | grep zip)
给我错误“无法打开“文件名(没有这样的文件或目录)”。相反,当我这样做时
file $(ls | grep zip)
无论文件夹如何,一切都会正常显示。为什么?这是某种论证限制吗?
如果我这样做
file $(ls Pictures/ | grep jpg)
我得到以下信息:
1234.jpg: ERROR: cannot open 1234.jpg (No such file or directory)
向右移动到我想要列出的目录时
nassosdim@ubuntu:~$ cd Pictures/
nassosdim@ubuntu:~/Pictures$ file $(ls | grep jpg)
打印出文件的结果
1234.jpg: JPEG image data, JFIF standard 1.01
有人可以向我解释一下发生了什么事吗? :(
答案1
出现错误是因为 bash 试图*
使用 glob 模式匹配将参数中的 扩展为 ls 。当 glob 与模式不匹配时,它总是会出现这样的错误。 then作为真正的星号*
传递ls
,它也不匹配文件,因此ls
会出错!
关于您正在做的事情,有几处是多余的。我知道您正在尝试学习一个结构,但让我们分解一下您刚刚完成的一些内容以及如何完成它。
ls /usr/bin
足以列出 bin 目录中的文件,您根本不需要星号。- 你永远不应该解析输出
ls
无论如何,它是模棱两可的并且有潜在的危险。 - 您可以通过执行以下操作获得相同的效果,而无需 grep
ls /usr/bin/*zip*
,但这ls
仍然是多余的,您可以将 glob 扩展传递给文件:file /usr/bin/*zip*
最后,find
通常是查找文件的更好工具。你可以像这样做你想做的事:
$ find /usr/bin -iname '*zip*' -exec file {} +
答案2
shell 扩展*
并将命令转换为file $(ls /usr/bin/a /usr/bin/b /usr/bin/whatever | grep zip)
.您不需要在 UNIX 中指定星号,除非您希望 shell 在将其传递到ls
.
即你的 shell 将 * 替换为每个匹配的文件前它运行命令,如果您习惯了的话,这不是它在 Windows 上的工作方式。
file $(ls /usr/bin/ | grep zip)
是正确的方法(从某种意义上说,您不需要 *,但请参阅 Caleb 的答案以了解其他问题和选项)。但请注意,实际上运行的是,
file /usr/bin/a /usr/bin/b /usr/bin/whatever
不是
file /usr/bin/a
file /usr/bin/b
file /usr/bin/whatever
再次强调,它的做法与 Windows 不同。
答案3
请尝试ls /usr/bin/* | grep zip
看看您正在提供哪些论据file
。我对结果有点困惑。在我的Ubuntu系统上,结果是这样的:
/usr/bin/funzip
/usr/bin/gpg-zip
/usr/bin/mzip
/usr/bin/preunzip
/usr/bin/prezip
/usr/bin/prezip-bin
/usr/bin/unzip
/usr/bin/unzipsfx
/usr/bin/zip
/usr/bin/zipcloak
/usr/bin/zipgrep
/usr/bin/zipinfo
/usr/bin/zipnote
/usr/bin/zipsplit
funzip
gpg-zip
mzip
preunzip
prezip
prezip-bin
unzip
unzipsfx
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit
使用ls /usr/bin/* | less
我们可以看到为什么会得到这样的结果:在 /usr/bin 中的所有文件之后,ls
还列出了 /usr/bin/X11 目录的内容,并且列出了它们,并且没有预先添加目录名称。
当您将这些没有目录名的文件名提供给 时file
,file
无法找到这些文件,并且您会收到“没有这样的文件或目录”错误消息(附注:如果您收到错误消息,请不要只说“我有错误”,但发布错误消息)。
就像 Caleb 已经发布的那样,只需使用file /usr/bin/*zip*
.
答案4
ls
由于输出格式各不相同,解析结果可能是一件有风险的事情。你最好做这样的事情:
file /path/to/*.zip
尝试使用更简单的命令来演示进程替换的工作原理:
ls $(echo /usr/bin)