Como executo vários comandos ao usar o find?

55

Estou tentando executar vários comandos em coisas que encontrei, como posso conseguir isso?

find . -exec cmd1; cmd2

parece não funcionar; Em vez disso, ele executa cmd2 após o cmd1 ter sido executado em todos os arquivos.

    
por Tom Wijsman 22.01.2011 / 22:52

5 respostas

40

Nesta demonstração, usarei sh -c 'echo first; false' (ou true ) para o primeiro -exec . Isso dará alguma saída e também terá o efeito de código de saída selecionado. Então echo second será usado para o segundo. Suponha que haja um arquivo no diretório atual.

$ find . -type f -exec sh -c 'echo first; false' \; -exec echo second \;
first
$ find . -type f -exec sh -c 'echo first; true' \; -exec echo second \;
first
second
$ find . -type f \( -exec sh -c 'echo first; false' \; -false -o -exec echo second \; \)
first
second
$ find . -type f \( -exec sh -c 'echo first; false' \; -false -o -exec echo second \; \)
first
second

Um comando real desse tipo seria parecido com:

find . -type f \( -exec command1 \; -false -o -exec command2 \; \)

No segundo conjunto, os parênteses com escape agrupam as duas cláusulas -exec . O -false entre eles força o estado de teste para "false" e o -o faz com que a próxima expressão (o segundo -exec ) seja avaliada por causa do -false .

De man find :

expr1 expr2
Two expressions in a row are taken to be joined with an implied "and"; expr2 is not evaluated if expr1 is false.

expr1 -a expr2
Same as expr1 expr2.

expr1 -o expr2
Or; expr2 is not evaluated if expr1 is true.

    
por 22.01.2011 / 23:15
32

Se você não importar que o cmd1 possa impedir que o cmd2 seja executado devido ao código de erro 0 :

find . -exec cmd1 \; -exec cmd2 \;

A única maneira confiável de obter os dois comandos para sempre executar isso é ter find invocar um shell que subseqüentemente executará os comandos em sequência:

find . -exec bash -c 'cmd1; cmd2' filedumper {} \;
    
por 22.01.2011 / 23:04
2

Se você não se importa em criar um script que faça cmd1 e cmd2, é exatamente isso:

find . -exec myscript {} \;

ou

find . -exec myscript {} +

Use \; ou + dependendo se o myscript pode manipular mais de um arquivo de cada vez (fica peludo se houver espaços em nomes de arquivos, etc).

Colocar o que você estava fazendo em um roteiro, na minha experiência, quase sempre valeu a pena. Se você tiver que fazer isso uma vez, terá que fazer de novo.

Mas um bom truque é colocar o encontro no script:

if [ $# -gt 0 ]; then
    for each; do
        touch $each
    done
else
    find . -exec $0 {} +
fi

Em seguida, o myscript funciona em quaisquer arquivos que você fornecer como argumentos para que ele funcione, mas se você não fornecer argumentos, ele será executado a partir do diretório atual e, em seguida, chamará os arquivos encontrados. Isso contorna o fato de que find -exec não pode chamar funções de shell que você definiu em seu script.

    
por 28.04.2016 / 19:00
0

Eu tenho tentado as duas soluções anteriores sem muita sorte. Este tem funcionado muito bem para mim:

$ for i in 'find . -exec echo {} \;'; do cmd1 $i; cmd2 $i; done
    
por 31.03.2016 / 04:17
-3

comando try:

sudo find -name "*[!0-9][1-9].txt" -exec chmod 744 * {} \; -a -exec ls -l {} \; | sort | parallel ls -l
    
por 24.11.2013 / 06:18