se o comando encontrar -exec

8

Eu estava apenas tentando listar todos os diretórios e arquivos no diretório atual e também escrever se eles são arquivos ou diretórios com o seguinte comando:

find -exec echo 'echo {} : ;if [ -f {} ]; then echo file; else echo directory;fi' \;

Eu sei que é um comando tolo, posso usar outras coisas como -type f ou -type d , mas quero saber por que esse trecho de código não funcionou como eu esperava. Apenas imprime diretório para todos eles. Por exemplo, enquanto a saída de find é:

.
./dir
./dir/file

a saída do meu código é:

. : directory
./dir : directory
./dir/file : directory

E saída de

echo 'echo dir/file : ;if [ -f dir/file ]; then echo file; else echo directory;fi'

é

dir/file : file

Estou trabalhando em Ubuntu 14.10 e usando find (GNU findutils) 4.4.2

    
por Esref 26.02.2015 / 23:00

2 respostas

12

Primeiro, seu snippet executa o comando

echo {} : ;if [ -f {} ]; then echo file; else echo directory;fi

porque precisa de sua saída para avaliar a substituição do comando. Como não há nenhum arquivo chamado {} , isso produz a saída

{} :
directory

Em seguida, o comando find é executado com os argumentos -exec , echo , {} , : , directory , portanto, para cada arquivo, ele exibe o nome do arquivo seguido por um espaço e : directory .

O que você realmente quer fazer é executar o fragmento de shell echo {} :; … em cada arquivo encontrado por find . Esse snippet deve ser executado por um shell gerado por find , não pelo shell que inicia find , pois está recebendo dados de find em sua linha de comando. Portanto, você precisa instruir find para executar um shell:

find -exec sh -c 'echo {} : ;if [ -f {} ]; then echo file; else echo directory;fi' \;

Isso é melhor, mas ainda não está certo. Ele funcionará com algumas (não todas) find implementações se os nomes dos arquivos não contiverem caracteres especiais, mas desde que você esteja interpolando o nome do arquivo em um shell script, você permite que nomes de arquivos executem comandos shell arbitrários, por exemplo. Se você tiver um arquivo chamado $(rm -rf /) , o comando rm -rf / será executado. Para passar nomes de arquivos para o script, passe-os como argumentos separados.

Além disso, o primeiro echo imprime uma nova linha depois dos dois pontos. Use echo -n (se o seu shell suportar) ou printf para evitar isso.

find -exec sh -c 'printf "%s :" "$0"; if [ -f "$0" ]; then echo file; else echo directory; fi' {} \;

Você pode usar -exec … {} + para agrupar invocações de shell, o que é mais rápido.

find -exec sh -c 'for x; do printf "%s :" "$x"; if [ -f "$x" ]; then echo file; else echo directory; fi; done' _ {} +
    
por 26.02.2015 / 23:22
2

Outra maneira de executar if; then; else; fi junto com find é:

find |
while read p; do if [ -f "$p" ]; then echo file; else echo directory; fi; done
    
por 17.09.2017 / 08:49