O que significa "{} \;" no comando find?

38

Às vezes, vejo o seguinte comando:

find . -name  * -exec ls -a {} \;

Me pediram para executar isso.

O que {} \;significa aqui?

codeofnode
fonte
2
-name *é redundante.
21413 Kevin
3
Verifique também o explicador para outros tipos de perguntas como esta. Aqui está a saída do seu comando. .
precisa saber é o seguinte
10
-name *é pior que redundante. Como *não está entre aspas, o shell o expande para a lista de nomes de arquivos na pasta atual, com espaços sendo tratados incorretamente, levando a resultados inesperados ou a uma mensagem de erro. Como ponto extra, findpossui muitas funções, uma delas para listar arquivos; isso evita ter que usar -exec. Por exemplo, você pode usar find . -printou find . -ls. Finalmente, há duas maneiras de escapar do ponto e vírgula: ou como você fez com a barra invertida, \;ou por citar: ';'. Use o que você se sentir mais confortável.
Paddy Landau

Respostas:

49

Se você executar findcom exec, {}expande para o nome do arquivo de cada arquivo ou diretório encontrado find(para que lsno seu exemplo obtenha todo nome de arquivo encontrado como argumento - observe que ele chama lsou qualquer outro comando que você especificar uma vez para cada arquivo encontrado).

O ponto e vírgula ;termina o comando executado por exec. Ele precisa ser escapado \para que o shell no qual você executa findnão o trate como seu próprio caractere especial, mas o repasse para find.

Veja este artigo para mais alguns detalhes.


Além disso, findfornece alguma otimização com exec cmd {} +- quando executado dessa maneira, findanexa os arquivos encontrados ao final do comando, em vez de invocá-lo uma vez por arquivo (para que o comando seja executado apenas uma vez, se possível).

A diferença de comportamento (se não em eficiência) é facilmente perceptível se executada com ls, por exemplo,

find ~ -iname '*.jpg' -exec ls {} \;
# vs
find ~ -iname '*.jpg' -exec ls {} +

Supondo que você tenha alguns jpgarquivos (com caminhos curtos o suficiente ), o resultado é uma linha por arquivo no primeiro caso e o lscomportamento padrão de exibir arquivos em colunas para o último.

moon.musick
fonte
11
Eu acho que seria benéfico para você para contrastar \;com +.
21413 Kevin
Como isso difere find . -name * | ls -a -?
András Hummer
@DrH O objetivo não é permitir que o shell faça a expansão de curinga, mas passe a expressão curinga para find. Além disso, a saída de ls, nesse caso, aparentemente não depende da entrada - não importa para o que eu uso como filtro find, lsapenas exibe o conteúdo do diretório de trabalho e é tudo. Verifique, por exemplo find ~ -iname '*.jpg' -exec ls -a {} \;vs find ~ -iname '*.jpg' | ls -a.
moon.musick
@DrH ou mesmo echo 'foo' | ls -a.
moon.musick
@ moon.musick, acredito que você perdeu o importante -em seu ls -a -comando ao testar o que o @ dr-h consultou.
22813 Daniel Llewellyn
21

Na página de manual do findcomandoÍcone da página de manual :

-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.  Both of these constructions might need to be escaped (with a  `\')  or
              quoted  to  protect them from expansion by the shell.

Então, aqui está a explicação:

{}significa "a saída de find". Como em "o que for findencontrado". findretorna o caminho do arquivo que você está procurando, certo? Então o {}substitui; é um espaço reservado para cada arquivo que o findcomando localiza (extraído daqui ).

A \;parte é basicamente dizendo find"ok, eu terminei com o comando que eu queria executar".

Exemplo:

Digamos que eu esteja em um diretório cheio de .txtarquivos. Então eu corro:

find . -name  '*.txt' -exec cat {} \;

A primeira parte find . -name *.txt,, retorna uma lista dos .txtarquivos. A segunda parte, -exec cat {} \;irá executar o catcomando para cada arquivo encontrado find, por isso cat file1.txt, cat file2.txte assim por diante.

Alaa Ali
fonte
4
A parte *.txtdeve ser citada como '*.txt'. Isso ocorre porque, se houver .txtarquivos na pasta atual, o shell expandirá isso e você obterá resultados incorretos ou uma mensagem de erro. find -name '*.txt' -exec cat {} \;
Paddy Landau
@Alaa Ali muito bem explicado
Pushya