“xargs”和“文件”出现奇怪的“没有这样的文件”错误

“xargs”和“文件”出现奇怪的“没有这样的文件”错误

我想获取当前目录下所有文件的 MIME 类型。为什么这不起作用?我已经在 OSX 或 Linux 上测试了 bash。 “file”抱怨它找不到该文件,但如果我使用完全相同的路径运行它,它就可以工作。

$ find . -type f | xargs -n 1 -I FILE echo $(file --mime-type -b FILE)
ERROR: cannot open './foo.txt' (No such file or directory)
...
$ file --mime-type -b ./foo.txt
text/plain

当然,在现实世界中,我不只是“回显”响应,我需要在另一个命令中使用 MIME 类型字符串。

这是我能解决的最简单的问题。我想我不明白有关xargs文件名替换的事情?

答案1

命令替换$(file --mime-type -b FILE)是由 shell 在传递给 之前执行的xargs,这就是为什么您没有看到您需要的内容。引用并通过 xargs$(file --mime-type -b FILE)传递它bash -c

find . -type f | xargs -n 1 -I FILE bash -c  'echo $(file --mime-type -b FILE)'

答案2

这里没有必要利用xargs。只需使用 的find开关即可-exec

$ find . -type f -exec file --mime-type -- {} +

例子

默认file输出

$ find 8* -type f -exec file --mime-type -- {} + | tail -5
89999/sample10.txt:               text/plain
89999/sample2.txt:                text/plain
89999/sample4.txt:                text/plain
89999/sample6.txt:                text/plain
89999/sample9.txt:                text/plain

file -b输出

$ find 8* -type f -exec file --mime-type -b -- {} + | head -5
application/x-empty
text/x-perl
text/plain
text/plain
text/plain

备择方案

这仅供参考,但还有另一个命令,称为mimetype,您也可以使用它来执行与 相同的操作file --mimetype。此命令是 Fedora 上此软件包的一部分perl-File-MimeInfo,其工作原理类似:

$ find 8* -type f -exec mimetype -- {} + | tail -5
89999/sample10.txt:               text/plain
89999/sample2.txt:                text/plain
89999/sample4.txt:                text/plain
89999/sample6.txt:                text/plain
89999/sample9.txt:                text/plain

更详细的执行

鉴于您询问“不仅仅是 echo..”,并且由于您正在尝试使用,xargs我将得出结论,您认为您需要使用xargs.

但如果您正在使用find,这通常不是最好的方法。您可以改为使用find,然后在find-execswitch 中调用 shell 并在此处执行更复杂的操作,而不是尝试xargs以更复杂的方式执行此操作。

$ find . -type f -exec sh -c '
   cmd1;
   cmd2;
   file --mime-type -b "$@";
   cmd3;
   cmd4;
 ' sh {} \;

笔记:我已经从使用+传递多个参数的终止符切换为file --mime-type ...一次\;传递一个参数。

例子

$ find 8* -type f -exec sh -c '
   echo -n "mime-type: "; 
   file --mime-type -b "$@"
  ' sh {} \; |& tail -10
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain
mime-type: text/x-shellscript
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain

答案3

您的问题与外壳扩展有关。 $() 在作为参数传递之前会被扩展。如果您想按原样对待它,请单引号它并为其调用 shell。

另外,如果您处理文件名,请养成使用 print0 和 0 的习惯,因为忽略它们会给您带来包含空格字符的文件名的问题。

例子:

find . -type f -print0 | xargs -0 -n 1 -I FILE bash -c 'echo $(file --mime-type -b FILE)'

在您的情况下,这可以简化为:

find . -type f -print0 | xargs -0 -n 1 file --mime-type -b

附加评论:为找到的所有文件调用程序(无论是“xargs -n 1”还是 find+exec)可能是真正的性能瓶颈。如果您的目录包含数千个文件,那么您将生成数千个进程。

相关内容