Compreendendo a opção -exec do find (1) (chaves e sinal de mais)


17

Usando o comando a seguir, alguém poderia explicar qual é exatamente o propósito dos chavetas finais ({}) e do sinal de mais (+)?

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

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

Respostas:


19

As chaves serão substituídas pelos resultados do findcomando e chmodserão executadas em cada uma delas. As +marcas findtentar executar o mínimo de comandos como possível (portanto, chmod 775 file1 file2 file3em oposição a chmod 755 file1, chmod 755 file2, chmod 755 file3). Sem eles, o comando apenas dá um erro. Tudo isso é explicado em man find:

-exec command ;

      Executar comando ; true se 0 status for retornado. Todos os argumentos a seguir findsão considerados argumentos para o comando até que um argumento que consiste em ' ;' seja encontrado. A string ' {}' é substituída pelo nome do arquivo atual sendo processado em todos os lugares em que ocorre nos argumentos do comando, não apenas nos argumentos em que está sozinho, como em algumas versões do find. ...

-exec command {} +

      Essa variante da -execação executa o comando especificado nos arquivos selecionados, mas a linha de comando é criada anexando cada nome de arquivo selecionado no final; o número total de invocações do comando será muito menor que o número de arquivos correspondentes. ...


12

Além da resposta de Terdon,

  • "Obviamente" -exec …deve ser terminado com um ponto-e-vírgula ( ;) ou um sinal de mais ( +). Ponto e vírgula é um caractere especial no shell (ou, pelo menos, a cada escudo que eu já utilizado), por isso, se é para ser usado como parte do findcomando , ele deve ser precedido ou cotados ( \;, ";"ou ';').
  • Com -exec … ;, a {}cadeia pode aparecer várias vezes no comando, incluindo zero ou duas ou mais, em qualquer posição.  Veja isso para um exemplo de por que você pode querer fazer -execsem usar {}.   Ter duas ou mais aparências é útil principalmente porque, em (pelo menos) algumas versões do find, {}não precisa ser uma palavra por si só; pode ter outros caracteres no começo ou no fim; por exemplo,

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

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

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

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

    • Uma solução alternativa específica para os comandos cpe 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 começo ou no final. E, em (pelo menos) algumas versões find, você pode não ter mais de uma {}.

  • Uma nota de sanidade: você pode dizer

    encontrar . -name "* .sh" -type f -executable -exec {} args opcionais aqui ";"

    para executar cada um dos seus scripts. Mas

    encontrar . -name "* .sh" -tipo f -executable -exec {} +

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

    ./*.sh
    

    como um comando shell, exceto findque não garante que ele classifique seus resultados, portanto você não tem garantia de execução aaa.sh (seu primeiro *.sharquivo em ordem alfabética ) como seria com a execução ./*.sh.

  • Um aspecto findque pode não estar perfeitamente claro para iniciantes é que a linha de comando é, efetivamente, uma declaração executável em um idioma misterioso. 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
    

    traduz para

    para cada arquivo
        se for um arquivo simples (ou seja, não um diretório)
        então
            execute o nome do arquivo grep -q cat
            se o processo for bem-sucedido (ou seja, sai com o status 0)
            então
                imprime o nome do arquivo
            fim se
        fim se
    laço final

    que imprimirá os nomes de todos os arquivos que contêm a string “ cat”. E, embora isso seja algo que greppossa ser feito sozinho (com a opção -l(minúscula L)), pode ser útil usá-lo findpara encontrar arquivos que contenham uma determinada string E tenham um determinado tamanho E sejam de propriedade de um determinado proprietário E foram modificados em um determinado intervalo de tempo,….

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

  • O outro lado da situação acima é que findgeralmente sai com um status de saída 0, a menos que você dê argumentos inválidos ou encontre um diretório que não pode ler. Mesmo se um programa que você executa falhar (sai com um status de saída diferente de zero), findsai com um status de saída igual a 0.  Exceto  se um programa que você executa com -exec … +falha (sai com um status de saída diferente de zero) findsai com um status de saída diferente de zero.

Além de um milhão de versões find(1) e testes do que findrealmente faz em alguns sistemas, o The Open Group Base Specifications Edição 7, 2013 Edition forneceu algumas informações sobre o que finddeve, pode e não deve ser feito.


3
Cuidado que seu exemplo de uso ... -exec mv {} {}.bak ...não é garantido para funcionar como esperado em todas as findimplementações. Os estados padrão POSIX {}devem parecer sozinhos para serem sempre reconhecidos; caso contrário, o comportamento é livre para manter os caracteres inalterados ou substituí-los pelo nome do caminho. No primeiro caso, o seu comando inteiro vai essencialmente apagar todos os arquivos, mas o último encontrado ...
jlliagre
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.