Como executo vários comandos ao usar o find?


57

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

find . -exec cmd1; cmd2

parece não funcionar; em vez disso, executa o cmd2 após a execução do cmd1 em todos os arquivos.

Respostas:


40

Nesta demonstração, usarei sh -c 'echo first; false'(ou true) para o primeiro -exec. Isso fornecerá alguma saída e também terá o efeito do código de saída selecionado. Então echo secondserá 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 semelhante a:

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

No segundo conjunto, os parênteses escapados agrupam as duas -execcláusulas. O -falseentre eles força o estado de teste a "falso" e -ofaz com que a próxima expressão (a segunda -exec) seja avaliada devido a -false.

De man find:

expr1 expr2
Duas expressões em uma linha são usadas para serem unidas com um "e" implícito; expr2 não é avaliado se expr1 for falso.

expr1 -a expr2 O
mesmo que expr1 expr2.

expr1 -o expr2
Or; expr2 não é avaliado se expr1 for verdadeiro.


Ah sim, eu esqueci -o.
Ignacio Vazquez-Abrams

32

Se você não importa se o cmd1 pode impedir a execução do cmd2 devido ao código de erro 0:

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

A única maneira confiável de obter sempre que ambos os comandos executem isso é findchamar um shell que posteriormente executará os comandos em sequência:

find . -exec bash -c 'cmd1; cmd2' filedumper {} \;

2

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

find . -exec myscript {} \;

ou

find . -exec myscript {} +

Usar \; ou + dependendo se o myscript pode lidar com mais de um arquivo por vez (fica peludo se houver espaços nos nomes dos arquivos, etc.).

Colocar o que você estava fazendo em um roteiro, na minha experiência, quase sempre valeu a pena. Se você precisar fazer isso uma vez, precisará fazê-lo novamente.

Mas um truque é colocar a descoberta dentro do script:

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

Em seguida, o myscript funciona em qualquer arquivo que você fornecer como argumento, mas se você não fornecer nenhum argumento, ele executará find a partir do diretório atual e se chamará nos arquivos encontrados. Isso contorna o fato de que find -exec não pode chamar funções de shell que você definiu em seu script.


0

Eu tenho tentado ambas as soluções anteriores sem muita sorte. Este funcionou muito bem para mim:

$ for i in `find . -exec echo {} \;`; do cmd1 $i; cmd2 $i; done

Isso não funcionará se a lista de arquivos for muito grande.
Alex

-3

comando try:

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

4
Não é uma boa ideia. O *na -execparte será expandido para todos os arquivos no diretório atual. Especialmente quando executando como sudo.
slhck
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.