Ian*_*anC 32 command-line ls pipe file-command
我一直在研究命令行并了解到|(pipeline) 旨在将命令的输出重定向到另一个命令的输入。那么为什么命令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]
Run Code Online (Sandbox Code Playgroud)
由于file命令的使用存在一些错误
Joh*_*man 70
根本问题是file期望文件名作为命令行参数,而不是标准输入。当你写ls | file的输出ls被作为输入传递给file. 不是作为参数,作为输入。
有什么不同?
命令行参数是在命令后写入标志和文件名时,如cmd arg1 arg2 arg3. 在shell脚本这些参数可以作为变量$1,$2,$3,等在C你会通过访问它们char **argv和int argc参数main()。
标准输入 stdin 是一个数据流。一些程序在没有给出任何命令行参数时喜欢cat或wc从 stdin 读取。在 shell 脚本中,您可以read用来获取单行输入。在 C 中,您可以在各种选项中使用scanf()或getchar()。
file通常不从标准输入读取。它期望至少有一个文件名作为参数传递。这就是为什么它会在您编写时打印出用法ls | file,因为您没有传递参数。
您可以使用xargs将 stdin 转换为参数,如ls | xargs file. 尽管如此,正如terdon 提到的,解析ls是一个坏主意。最直接的方法很简单:
file *
Run Code Online (Sandbox Code Playgroud)
ter*_*don 18
因为,正如你所说,输入file必须是filenames。ls但是,的输出只是文本。它恰好是一个文件名列表并不会改变它只是文本而不是硬盘驱动器上文件位置的事实。
当您看到打印在屏幕上的输出时,您看到的是文本。无论该文本是一首诗还是一个文件名列表,对计算机来说都没有区别。它只知道它是文本。这就是为什么您可以将 的输出传递ls给将文本作为输入的程序(尽管您真的,真的不应该):
$ ls / | grep etc
etc
Run Code Online (Sandbox Code Playgroud)
因此,要使用将文件名作为文本(例如ls或find)列出的命令的输出作为采用文件名的命令的输入,您需要使用一些技巧。典型的工具是xargs:
$ ls
file1 file2
$ ls | xargs wc
9 9 38 file1
5 5 20 file2
14 14 58 total
Run Code Online (Sandbox Code Playgroud)
但是,正如我之前所说,您真的不想解析ls. 类似的东西find更好(在每个文件名之后print0打印 a\0而不是 newilne 并且-0ofxargs让它处理此类输入;这是使您的命令与包含换行符的文件名一起使用的技巧):
$ find . -type f -print0 | xargs -0 wc
9 9 38 ./file1
5 5 20 ./file2
14 14 58 total
Run Code Online (Sandbox Code Playgroud)
这也有自己的方式来做到这一点,xargs根本不需要:
$ find . -type f -exec wc {} +
9 9 38 ./file1
5 5 20 ./file2
14 14 58 total
Run Code Online (Sandbox Code Playgroud)
最后,您还可以使用 shell 循环。但是,请注意,在大多数情况下,xargs速度会更快、效率更高。例如:
$ for file in *; do wc "$file"; done
9 9 38 file1
5 5 20 file2
Run Code Online (Sandbox Code Playgroud)
ls通过管道的输出是一个实心数据块,每行以 0x0a 分隔 - 即换行符 - 并将file其作为一个参数获取,它期望多个字符一次处理一个。
作为一般规则,永远不要使用ls为其他命令生成数据源 - 有一天它会通过管道 .. 进入rm,然后你就有麻烦了!
最好使用循环,例如for i in *; do file "$i" ; done它会以可预测的方式产生您想要的输出。如果文件名带有空格,则有引号。
| 归档时间: |
|
| 查看次数: |
7983 次 |
| 最近记录: |