我一直在研究命令行并了解到|
(管道)旨在将输出从命令重定向到另一个命令的输入。那么为什么命令ls | file
不起作用呢?
file
输入是多个文件名之一,例如file filename1 filename2
ls
输出是文件夹上的目录和文件列表,所以我认为ls | file
应该显示文件夹上每个文件的文件类型。
但是,当我使用它时,输出是:
Usage: file [-bcEhikLlNnprsvz0] [--apple] [--mime-encoding] [--mime-type]
[-e testname] [-F separator] [-f namefile] [-m magicfiles] file ...
file -C [-m magicfiles]
file [--help]
由于该file
命令的使用存在一些错误
根本问题是
file
期望文件名作为命令行参数,而不是标准输入。当您编写ls | file
的输出ls
作为输入传递给file
. 不作为参数,作为输入。有什么不同?
命令行参数是当您在命令后写入标志和文件名时,如
cmd arg1 arg2 arg3
. 在 shell 脚本中,这些参数可用作变量$1
、$2
、$3
等。在 C 中,您可以通过char **argv
和int argc
参数访问它们main()
。标准输入 stdin 是一个数据流。一些程序在没有任何命令行参数时喜欢
cat
或从标准输入读取。wc
在 shell 脚本中,您可以使用它read
来获取单行输入。在 C 中,您可以在各种选项中使用scanf()
or 。getchar()
file
通常不从标准输入读取。它期望至少有一个文件名作为参数传递。这就是为什么它会在您编写时打印出用法ls | file
,因为您没有传递参数。您可以使用
xargs
将标准输入转换为参数,如ls | xargs file
. 尽管如此,正如terdon 提到的,解析ls
是一个坏主意。最直接的方法就是:因为,正如您所说,的输入
file
必须是filenames。ls
然而,的输出只是文本。它恰好是文件名列表并没有改变它只是文本而不是硬盘驱动器上文件位置的事实。当您看到屏幕上打印的输出时,您看到的是文本。该文本是一首诗还是一个文件名列表对计算机没有影响。它只知道它是文本。这就是为什么您可以将 的输出传递
ls
给将文本作为输入的程序(尽管您真的,真的不应该):因此,要使用将文件名列为文本(例如
ls
或find
)的命令的输出作为采用文件名的命令的输入,您需要使用一些技巧。典型的工具是xargs
:不过,正如我之前所说,您真的不想解析
ls
. 类似的东西find
更好(在每个文件名之后print0
打印 a\0
而不是 newilne ,而-0
ofxargs
让它处理这样的输入;这是使您的命令与包含换行符的文件名一起工作的技巧):它也有自己的方法,
xargs
根本不需要:最后,您还可以使用 shell 循环。但是,请注意,在大多数情况下,
xargs
会更快、更有效率。例如:它不会“重定向”输出,而是获取程序的输出并将其用作输入,而 file 不接受输入,而是将文件名作为参数,然后对其进行测试。重定向不会将这些文件名作为参数传递,管道也不会,您正在做的事情越晚。
--files-from
如果您有一个列出所有要测试的文件的文件,您可以做的是从文件中读取文件名,否则只需将文件的路径作为参数传递。接受的答案解释了为什么管道命令不能立即工作,并且使用该
file *
命令,它提供了一个简单、直接的解决方案。我想提出另一种可能在某个时候派上用场的替代方案。诀窍是使用反引号
(`)
字符。反引号在这里有非常详细的解释。简而言之,它获取包含在反引号中的命令的输出,并将其作为字符串替换为剩余的命令。因此,
find `ls`
将获取ls
命令的输出,并将其替换为find
命令的参数。这比公认的解决方案更长、更复杂,但它的变体在其他情况下可能会有所帮助。通过管道的输出
ls
是一个实心数据块,每行以 0x0a 分隔 - 即换行符 - 并将file
其作为一个参数,它期望多个字符一次处理一个。作为一般规则,永远不要使用
ls
为其他命令生成数据源 - 有一天它会通过管道 .. 进入rm
,然后你就有麻烦了!最好使用循环,例如
for i in *; do file "$i" ; done
可以预测地产生您想要的输出。如果文件名带有空格,则会出现引号。如果您想使用管道来馈送,请使用通常后跟文件名
file
的选项,但您也可以使用单个连字符从标准输入读取,所以-f
-
连字符的技巧
-
适用于许多标准命令行实用程序(尽管--
有时是这样),所以它总是值得一试。该工具
xarg
功能更强大,并且在大多数情况下仅在参数列表太长时才需要(有关详细信息,请参阅此帖子)。它可以使用如下命令
它对我来说会更好
这也应该有效:
在这里也讨论过:https ://unix.stackexchange.com/questions/5778/whats-the-difference-between-stuff-and-stuff