在this问题中答案是
find . -type f -name \*.mp4 -exec sh -c 'ffprobe "$0" 2>&1 |
grep -q 1920x1080 && echo "$0"' {} \;
将输出1920x1080
的所有mp4文件。
我不明白为什么sh -c
存在。如果我删除它,那么它找不到任何东西。
作者说
新shell需要处理exec'd中的流控制 命令。
但我想我缺少一些了解答案的基本知识。
问题
任何人都可以解释为什么sh -c
必须存在,以及为什么只有ffprobe
才能在新shell中打开?
答案 0 :(得分:6)
-exec选项采用一系列参数:
find . -exec arg0 arg1 arg2 ... \;
如果你把参数放在引号
中find . -exec "arg0 arg1 arg2" \;
然后将“arg0 arg1 arg2”视为单个参数。它期望在您的系统上存在名为arg0 arg1 arg2
的带有空格的命令,而不是名为arg0
的命令,其参数为arg1
和arg2
。
如果您在没有sh -c
的情况下使用find,那么您将拥有:
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 {} \;
但是,不是单独的脚本,一切都在一条线上。
答案 1 :(得分:5)
find
直接执行给exec
作为命令的参数(即它将第一个参数作为具有以下参数的应用程序作为该命令的参数调用),而不对其进行任何处理而不是用文件名替换{}
。也就是说,它没有实现任何shell功能,如管道或输入重定向。在您的情况下,该命令包含管道和输入重定向。因此,您需要通过sh
运行命令,以便sh
处理这些命令。
答案 2 :(得分:1)
区别在于find
的实施。 Find使用Linux / Unix(Posix)的fork()
和exec()
调用的风格来生成一个新进程并将带有参数的命令传递给它。 exec()
调用运行可执行文件(二进制或shebang解释程序),将参数作为参数字符串直接传递给它。没有处理这些参数。
因此不解释shell约定。例如。 $0
,2>&1
和'|'等作为参数传递给fprobe
。不是你想要的。通过添加sh -c
,您告诉find
执行 shell ,将其余行传递给它进行解释。
请注意,将命令放在shebang脚本中并从find
调用此脚本可以获得相同的效果。这里exec的脚本会加载shell。