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' _ {} +