A resposta de muru é apropriada e adequada para os casos em que queremos imprimir algo se o arquivo for encontrado. Para casos gerais, quando queremos executar um comando externo, como echo
, poderíamos usar -exec
flag.
$ find . -name 'xac' -exec echo "I found " {} \; -quit
I found ./xac
A {}
parte passa o nome do arquivo para o comando entre -exec
e \;
como argumentos. Observe o \
antes ;
- ele impede que o shell o interprete errado ; no ponto e vírgula de fechamento do shell significa fim do comando, mas quando escapado com barra, o shell o tratará como texto literário a ser passado ao find
comando e, para encontrar o comando, ele serve como -exec
argumento de fechamento da flag.
Para construir condicionais do if found do this; else do that
tipo, poderíamos fazer uso da subestação de comando $()
e test
comando (aka [
):
$ [ "x$(find . -name 'noexist' -print -quit)" != "x" ] && echo "found" || echo "not found"
not found
$ [ "x$(find . -name 'xac' -print -quit)" != "x" ] && echo "found" || echo "not found"
found
Dirigindo-se ao comentário de Dan
Dan nos comentários perguntou:
O eco "Encontrei {}" não seria melhor do que o eco "Encontrei" {}? Talvez para eco seja bom, mas se alguém copia o comando e substitui o eco por outro comando, pode haver um problema
Vamos entender o problema primeiro. Normalmente, em shells existe o conceito de divisão de palavras, o que significa que variáveis não citadas e parâmetros posicionais serão expandidos e tratados como itens separados. Por exemplo, se você tiver variável var
e contém hello world
texto, quando você faz touch $var
o shell vai dividi-la em dois itens separados hello
e world
e touch
vai entender que, como se estivesse tentando criar 2 arquivos separados; se o fizer touch "$var"
, o shell tratará hello world
como uma unidade e touch
criará apenas um arquivo. É importante entender que isso acontece apenas devido à forma como as conchas funcionam.
Por outro lado, find
não sofre com esse comportamento, porque os comandos são processados por find
si só e executados por execvp()
chamada do sistema, portanto, não há shell envolvido. Enquanto os chavetas têm um significado especial nas conchas, porque elas aparecem no meio do find
comando e não no começo, elas não possuem significado especial para descascar nesse caso. Aqui está um exemplo. Vamos criar alguns nomes de arquivos difíceis e tentar transmiti-los como argumento para stat
comando.
$ touch with$'\t'tab.txt with$' 'space.txt with$'\n'newline.txt
$ find -type f -exec stat -c "%F" {} \; -print
regular empty file
./with?newline.txt
regular empty file
./with space.txt
regular empty file
./with?tab.txt
Como você pode ver, stat
recebe nomes de arquivos difíceis perfeitamente find
, o que é um dos principais motivos pelos quais é recomendado para uso em scripts portáteis e especialmente útil quando você está percorrendo a árvore de diretórios e deseja fazer algo com nomes de arquivos que possam ter potencialmente caracteres especiais neles. Portanto, não é necessário citar chaves para comandos executados no find
.
É uma história diferente quando a shell se envolve. Às vezes, você precisa usar um shell para processar o nome do arquivo. Nesse caso, a citação será realmente importante, mas é importante perceber que o problema não é do achado - é o shell que faz a divisão de palavras.
$ find -type f -exec bash -c "stat {}" sh \;
stat: cannot stat './with': No such file or directory
sh: line 1: newline.txt: command not found
stat: cannot stat './with': No such file or directory
stat: cannot stat 'space.txt': No such file or directory
stat: cannot stat './with': No such file or directory
stat: cannot stat 'tab.txt': No such file or directory
Então, quando citamos dentro do shell , ele funcionará. Mas, novamente, isso é importante para o shell, não find
.
$ find -type f -exec bash -c "stat -c '%F' '{}'" sh \;
regular empty file
regular empty file
regular empty file
/some/path
diz para descobrir onde começar a procurar, mas nada diz o que procurar. O mesmo na sua resposta vinculada. O que funciona para mim éfind /some/path -name xac -print0 -quit | grep -qz . && echo found
. Perdi algo?