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


17

使用以下命令,有人可以解释到底花括号({})和加号(+)的确切含义是什么?

如果将它们从命令中排除,该命令将如何以不同的方式运行?

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

Answers:


19

花括号将由find命令结果替换,并且chmod将在每个花括号上运行。该+品牌find试图以尽可能少的命令运行(这样,chmod 775 file1 file2 file3相对于chmod 755 file1chmod 755 file2chmod 755 file3)。没有它们,该命令将给出错误。有关所有内容,请参见man find

-exec command ;

      执行命令 ; 如果返回0状态,则为true。后面的所有自变量find都是命令的自变量,直到;遇到由' ' 组成的自变量为止。字符串' {}'被当前文件名替换,该文件名在命令的参数中出现的任何位置处都会被处理,而不仅仅是在单独使用的参数中(如在某些版本中)find。…

-exec command {} +

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


12

除了terdon的答案,

  • “显然” -exec …必须以分号(;)或加号(+)结尾。分号是在shell(或者,至少,每个shell我曾经使用过)的特殊字符,因此,如果它是用来作为的一部分find命令,它必须转义或引用(\;";",或';')。
  • 使用-exec … ;{}字符串可以在命令中出现任意次,包括在任何位置出现0或两次或更多次。  请参阅 示例,了解为什么-exec不使用可能想要做的事情{}  出现两次或多次出现是很有用的,主要是因为(至少在的某些版本中)find{}单词本身不必是一个单词。它的开头或结尾可以有其他字符;例如,

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

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

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

    导致出现神秘find: missing argument to ‘-exec’错误消息。

    • 针对于cpand mv命令的解决方法是

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

      要么

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

    {}必须是本身就是一个字; 开头或结尾不能有其他字符。并且,在(至少)某些版本中find,您可能没有多个{}

  • 注意事项:您可以说

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

    运行每个脚本。但

    找 。-name“ * .sh” -type f -executable -exec {} +

    运行一个脚本中,与所有其他的参数的名称。这类似于说

    ./*.sh
    

    作为shell命令,除了find不能保证对结果进行排序,因此不能保证您可以像运行aaa.sh run *.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(小写L)选项),但将其用于find查找包含特定字符串且具有特定大小并且由特定所有者拥有的文件可能会很有用。在一定时间范围内对AND进行了修改,…。

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

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

除了一百万个版本find(1) 并测试find在两个系统上的实际功能外, The Open Group基本规范第7版,2013年版还 提供了有关find必须,可以和不可以执行的操作的一些信息。


3
请注意,您使用的示例... -exec mv {} {}.bak ...并不保证在所有find实现中都能正常工作。POSIX标准状态{}必须单独出现才能始终被识别,否则可以自由地使字符保持不变或用路径名替换它们。在前一种情况下,您的整个命令实际上将删除除找到的最后一个文件以外的所有文件...
jlliagre
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.