4

这个问题中,答案是

find . -type f -name \*.mp4 -exec sh -c 'ffprobe "$0" 2>&1 |
   grep -q 1920x1080 && echo "$0"' {} \;

这将输出所有 .mp4 文件1920x1080

我不明白为什么sh -c会在那里。如果我删除它,那么它什么也找不到。

作者说

需要新的 shell 来处理 exec'd 命令中的流控制。

但我想我缺少一些基本知识来理解答案。

问题

谁能解释为什么sh -c必须在那里,为什么它只能ffprobe在新的外壳中打开?

4

3 回答 3

6

-exec 选项采用一系列参数:

find . -exec arg0 arg1 arg2 ... \;

如果您将参数放在引号中

find . -exec "arg0 arg1 arg2" \;

然后 "arg0 arg1 arg2" 被视为单个参数。它会期望arg0 arg1 arg2在您的系统上存在一个名为 的命令,带有空格,而不是arg0使用参数arg1和调用的命令arg2

如果您要使用 find 而不使用sh -c,那么您将拥有:

find . -type f -name \*.mp4 -exec 'ffprobe "{}" 2>&1 |
   grep -q 1920x1080 && echo "{}"' \;

这意味着find它将寻找一个名为 的命令ffprobe "$0" ....,不传递任何参数——没有这样的命令。有一个名为 的命令ffprobe,它接受参数,这就是您所需要的。一种可能性是做这样的事情:

find . -type f -name \*.mp4 -exec ffprobe '$0' 2>&1 |
   grep -q 1920x1080 && echo '{}' \;

但是,这不起作用,因为输出重定向2>&1以及管道|和命令序列运算符的&&处理方式都与您想要的不同。

为了解决这个问题,他们使用了另一个 shell。这类似于创建一个脚本来完成这项工作:

find . -type f -name \*.mp4 -exec myscript {} \;

但不是单独的脚本,而是所有内容都在一行中。

于 2013-05-12T16:20:38.690 回答
5

find直接执行exec作为命令提供的参数(即它调用第一个参数作为应用程序,并使用以下参数作为该命令的参数)而不对其进行任何处理,而不是用{}文件名替换。也就是说,它没有实现任何 shell 功能,如管道或输入重定向。在您的情况下,该命令包含管道和输入重定向。所以你需要通过 运行命令sh,以便sh处理这些。

于 2013-05-12T16:21:58.807 回答
1

不同之处在于find. Find 使用 Linux/Unix (Posix) 的风格fork()exec()调用来生成一个新进程并将带有参数的命令传递给它。该exec()调用运行一个可执行文件(二进制或 shebang 解释程序),将参数作为参数字符串直接传递给它。没有处理这些参数。

因此不解释 shell 约定。例如$0,2>&1和 '|' fprobe等作为参数传递给。不是你想要的。通过添加sh -c,您是在告诉findexec 一个shell,并将该行的其余部分传递给它以进行解释。

请注意,您可以通过将命令放入 shebang 脚本并从find. 此处执行的脚本将加载 shell。

于 2013-05-12T16:36:41.913 回答