【问题标题】:What is Flow Control in Bash?什么是 Bash 中的流控制?
【发布时间】:2013-05-13 00:36:41
【问题描述】:

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 中打开?

【问题讨论】:

    标签: linux bash


    【解决方案1】:

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

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

    如果你把参数放在引号里

    find . -exec "arg0 arg1 arg2" \;
    

    然后 "arg0 arg1 arg2" 被视为单个参数。它会期望一个名为arg0 arg1 arg2 的命令存在于您的系统上,而不是一个名为arg0 的命令,其参数为arg1arg2

    如果您要使用不带 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 {} \;
    

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

    【讨论】:

    • 这部分也是由于unistd.h 中的exec* 函数。很可能(我还没有阅读 GNU find 的源代码)他们正在使用类似 execve 的东西,所以你是正确的,这些函数的第一个参数必须是运行的二进制文件(可执行文件)。该字符串将被视为一个大型可执行文件并会导致错误。它们大多(如果不是全部)采用字符串数组或可变数量的参数作为传递的其余参数。
    • 我真的很惊讶$0 被解释为它在单引号内。为什么会这样?
    • @SandraSchlichting: $0 在另一个外壳中被替换,它看不到单引号。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

      请注意,您可以通过将命令放入 shebang 脚本并从 find 调用此脚本来获得相同的效果。此处执行的脚本将加载 shell。

      【讨论】:

        猜你喜欢
        • 2013-04-09
        • 1970-01-01
        • 2011-04-23
        • 2021-08-29
        • 1970-01-01
        • 2016-03-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多