了解 find(1) 的 -exec 选项(大括号和加号)

了解 find(1) 的 -exec 选项(大括号和加号)

使用以下命令,有人可以解释一下结尾大括号 ({}) 和加号 (+) 的确切用途吗?

如果他们被排除在命令之外,命令的运作会有什么不同?

find . -type d -exec chmod 775 {} +

答案1

大括号将被命令的结果替换find,并且chmod将在每个命令上运行。 make+尝试find运行尽可能少的命令(因此,与, ,chmod 775 file1 file2 file3相反)。如果没有它们,该命令只会给出错误。这一切都在chmod 755 file1chmod 755 file2chmod 755 file3man find:

-exec command ;

      执行命令;如果返回 0 状态则为 true。以下所有参数find被视为命令的参数,直到;遇到由 ' ' 组成的参数。字符串 ' {}' 会被命令参数中出现的所有地方处理的当前文件名替换,而不仅仅是在单独出现的参数中,如在某些版本中find。 ……

-exec command {} +

      -exec操作的变体对选定的文件运行指定的命令,但命令行是通过在末尾附加每个选定的文件名来构建的;该命令的调用总数将远小于匹配的文件数。 ……

答案2

除了特登的回答之外,

  • “显然”必须以分号 ( ) 或加号 ( )-exec …结尾。分号是 shell 中的特殊字符(或者至少是我曾经使用过的每个 shell),因此,如果要使用它;+find作为命令的一部分,它必须被转义或引用(\;, ";", 或';')。
  • 使用 时-exec … ;,该{}字符串可以在命令中出现任意多次,包括零,或两个或更多,在任何位置。  举例说明为什么您可能不想-exec使用{}.  具有两个或多个外观是有用的,主要是因为,(至少)在 的某些版本中find{}本身不需要是一个单词;它的开头或结尾可以有其他字符;例如,

    find . -type f -exec mv {} {}.bak ";"
    

    -exec … +,{}字符串必须作为 之前的最后一个参数出现+。像这样的命令

    find . -name "*.bak" -exec mv {} backup_folder +
    

    结果出现神秘的find: missing argument to ‘-exec’错误消息。

    • 特定于cpmv命令的解决方法是

      find . -name "*.bak" -exec mv -t backup_folder {} +
      

      或者

      find . -name "*.bak" -exec mv --target-directory=backup_folder {} +
      

    The{}本身必须是一个词;它的开头或结尾不能有其他字符。而且,(至少)在 的某些版本中find,您可能不会有多个{}.

  • 理智说明:你可以说

    寻找 。 -name "*.sh" -type f -executable -exec {}此处可选参数“;”

    运行每个脚本。但

    寻找 。 -name "*.sh" -type f -executable -exec {} +

    运行您的脚本的名称,所有其他脚本的名称作为参数。这类似于说

    ./*.sh
    

    作为 shell 命令, exceptfind不保证它对其结果进行排序,因此不能保证您可以像运行 一样运行aaa.sh (按字母顺序排列的第一个文件) 。*.sh./*.sh

  • find初学者可能不太清楚的一个方面是,命令行实际上是一个可执行语句用一种神秘的语言。例如,

    find . -name "*.sh" -type f -executable -print
    

    方法

    for each file
        if the file’s name matches `*.sh` (i.e., if it ends with `.sh`)
        then
            if it is a plain file (i.e., not a directory)
            then
                if it is executable (i.e., the appropriate `---x--x--x` bit is set)
                then
                    print the file’s name
                end if
            end if
        end if
    end loop
    

    或者,简单地说,

    for each file
        if the file’s name matches `*.sh`  AND  it is a plain file  AND  it is executable
        then
            print the file’s name
        end if
    end loop
    

    有些-关键字既是可执行操作又是测试。特别是,对于-exec … ;;例如,

    find . -type f -exec grep -q cat {} ";" -print
    

    翻译为

    对于每个文件
        如果它是一个普通文件(即不是目录)
        然后
            执行 grep -q cat文件名
            如果进程成功(即以状态 0 退出)
            然后
                打印文件名
            万一
        万一
    结束循环

    这将打印包含字符串“”的所有文件的名称cat。而且,虽然这是grep可以单独完成的事情(使用-l(lower-case ) 选项),但将它与查找包含特定字符串且具有特定大小且由特定所有者拥有的文件L可能很有用find并且在一定的时间范围内进行了修改,……。

    但是,这不适用于-exec … +.由于-exec … +对多个文件执行一个命令,因此将其用作for each file …循环内的逻辑条件是没有意义的。

  • 上述情况的另一面是,find通常以退出状态 0 退出,除非您给它提供无效的参数或者它遇到无法读取的目录。即使您执行的程序失败(以非零退出状态退出), find也会以退出状态 0 退出。  除了 如果您执行的程序-exec … +失败(以非零退出状态退出), find将以非零退出状态退出。

除了一百万个版本find(1) 并测试find在几个系统上实际执行的操作之外, The Open Group 基本规范第 7 期,2013 年版find提供了一些关于必须做什么、可以做什么和不可以做什么的 信息。

相关内容