Noções básicas sobre a opção -exec do find (1) (chaves e sinal de mais)

12

Usando o seguinte comando, alguém poderia explicar qual é exatamente o propósito das chaves de encerramento ({}) e sinal de mais (+)?

E como o comando funcionaria de maneira diferente se eles fossem excluídos do comando?

find . -type d -exec chmod 775 {} +
    
por Ryan Prentiss 09.05.2015 / 11:21

2 respostas

17

As chaves serão substituídas pelos resultados do comando find , e o chmod será executado em cada um deles. O + faz com que find tente executar o mínimo de comandos possível (assim, chmod 775 file1 file2 file3 em oposição a chmod 755 file1 , chmod 755 file2 , chmod 755 file3 ). Sem eles, o comando apenas dá um erro. Isso tudo é explicado em man find :

   -exec command ;
          Execute  command;  true  if 0 status is returned.  All following
          arguments to find are taken to be arguments to the command until
          an  argument  consisting of ';' is encountered.  The string '{}'
          is replaced by the current file name being processed  everywhere
          it occurs in the arguments to the command, not just in arguments
          where it is alone, as in some versions of find.  

   -exec command {} +
          This  variant  of the -exec action runs the specified command on
          the selected files, but the command line is built  by  appending
          each  selected file name at the end; the total number of invoca‐
          tions of the command will  be  much  less  than  the  number  of
          matched  files.   
    
por 09.05.2015 / 11:28
10

Além da resposta de terdon,

  • "Obviamente" -exec … deve ser terminado com um ponto-e-vírgula ( ; ) ou um sinal de mais ( + ). O ponto e vírgula é um caractere especial no shell (ou, pelo menos, todas as conchas que já usei), então, se é para ser usado como parte do comando find , deve ser escapado ou cotado ( \; , ";" ou ';' ).
  • Com -exec … ; , a string {} pode aparecer qualquer número de vezes no comando, incluindo zero , ou dois ou mais, em qualquer posição. Veja este por um exemplo de por que você pode querer fazer -exec sem usar {} . Ter duas ou mais aparências é útil principalmente porque, em (pelo menos) algumas versões de find , o {} não precisa ser uma palavra por si só; pode ter outros personagens no começo ou no final; por exemplo,

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

    com -exec … + , a {} string deve aparecer como o último argumento antes do + . Um comando como

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

    resulta na mensagem de erro find: missing argument to ‘-exec’ enigmática.

    • Uma solução alternativa para isso, específica dos comandos cp e mv , é

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

      ou

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

    O {} deve ser uma palavra por si só; não pode ter outros caracteres no início ou no final. E, em (pelo menos) algumas versões de find , você pode não ter mais de um {} .

  • Uma nota de sanidade: você pode dizer

    find . -name "*.sh" -type f -executable -exec {} optional args here ";"

    para executar cada um dos seus scripts. Mas

    find . -name "*.sh" -type f -executable -exec {} +

    executa um dos seus scripts, com os nomes de todos os outros como parâmetros. Isso é semelhante a dizer

    ./*.sh
    

    como um comando shell exceto find não garante que ordene seus resultados, então você não tem garantia de executar aaa.sh (seu primeiro arquivo alfabético *.sh ) como você estaria executando ./*.sh .

  • Um aspecto de find que pode não estar perfeitamente claro para iniciantes é que a linha de comando é, efetivamente, uma instrução executável em uma linguagem arcana. Por exemplo,

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

    significa

    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
    

    ou simplesmente,

    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
    

    Algumas das palavras-chave - são uma ação executável e um teste. Em particular, isso é verdade para -exec … ; ; por exemplo,

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

    se traduz para

    for each file
        if it is a plain file (i.e., not a directory)
        then
            execute         grep -q cat filename
            if the process succeeds (i.e., exits with status 0)
            then
                print the file’s name
            end if
        end if
    end loop

    , que imprimirá os nomes de todos os arquivos que contiverem a string “ cat ”. E, enquanto isso é algo que grep pode fazer por si só (com a opção -l (letra minúscula L )), pode ser útil para usá-lo com find para encontrar arquivos que contenham uma certa string E ter um certo tamanho E são de propriedade de um determinado proprietário E foram modificados em um determinado intervalo de tempo,….

    No entanto, isso não funciona para -exec … + . Como -exec … + executa um comando para vários arquivos, não faz sentido usá-lo como condição lógica dentro de um loop for each file … .

  • O outro lado do texto acima é que find geralmente sai com um status de saída de 0, a menos que você forneça argumentos inválidos ou encontra um diretório que não pode ler. Mesmo se um programa que você executar falhar (sai com um status de saída diferente de zero), find sairá com um status de saída de 0. Exceto se um programa que você executar com -exec … + falhar (sai com um status de saída diferente de zero), find sairá com um status de saída diferente de zero.

Além de um milhão de versões de find(1) e testar o que o find realmente faz em alguns sistemas, Especificações do Open Group Base Issue 7, edição 2013 forneceu algumas das informações sobre o que find deve, pode e não deve fazer.

    
por 09.05.2015 / 14:13

Tags