Usando conectores após o comando find

10

Eu quero que meu bash imprima 'found' somente se algo for encontrado, usando o comando find. Mas usando & & não ajuda: mesmo que não encontrei nada, estou sendo 'encontrado' impresso. Exemplo:

$ pwd
/data/data/com.termux/files/home/test/test1/test4
$ ls
xaa  xab
$ find . -name xac && echo 'found'
found
$ find . -name xaa && echo 'found'
./xaa
found
    
por Josef Klimuk 31.10.2017 / 06:35

2 respostas

18

Você pode fazer find imprimir found :

find . -name xac -printf "found\n" -quit

O -quit fará com que find saia depois da primeira correspondência , por isso found é apenas impresso no máximo uma vez.

Em um tópico semelhante no Unix & Linux ( fazer a descoberta falhar quando nada foi encontrado ), usei grep -qz para retornar um status de saída diferente de zero se find não encontrou nada:

find /some/path -print0 -quit | grep -qz .

Que você pode usar para construir comandos compostos usando && ou if :

find /some/path -print0 -quit | grep -qz . && echo found
    
por muru 31.10.2017 / 06:38
13

a resposta do muru é apropriada e adequada para 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 de ; - ele impede que o shell interprete incorretamente ; no ponto-e-vírgula de fechamento de shell significa fim de comando, mas quando escapado com barra, o shell o tratará como texto literal a ser passado para o comando find comando serve como fechamento argumentos% flag -exec .

Para construir condicionais do if found do this; else do that sort, poderíamos usar o comando% subcomissão$() e test (também conhecido como [ ):

$ [ "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:

Wouldn't echo "I found {}" be better than echo "I found " {}? Maybe for echo it's fine, but if someone copies the command and replaces echo with another command, they may have a problem

Vamos entender o problema primeiro. Normalmente, em shells há 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 a variável var e contiver hello world text, quando você fizer touch $var , o shell a dividirá em dois itens separados hello e world e touch entenderão que, como se você estava tentando criar dois arquivos separados; se você fizer touch "$var" , o shell tratará hello world como uma unidade e touch criará apenas um arquivo. Isso é importante para entender que isso acontece apenas devido a como os shells funcionam.

Por contraste, find não sofre com tal comportamento, porque os comandos são processados por find e executados por execvp() system call, portanto não há shell envolvido. Embora chaves tenham um significado especial em shells, porque elas aparecem no meio do comando find , e não no começo, elas não têm significado especial para shell neste caso. Aqui está um exemplo. Vamos criar alguns nomes de arquivos difíceis e tentar passá-los como argumento para o comando stat .

$ 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 arquivo difíceis perfeitamente com find , que é uma das principais razões pelas quais é recomendado para uso em scripts portáteis e especialmente útil quando você está percorrendo a árvore de diretórios e deseja para fazer algo com nomes de arquivos que podem ter caracteres especiais. Portanto, não é necessário citar chaves para os comandos executados em find .

É uma história diferente quando o shell se envolve. Às vezes você precisa usar um shell para processar o nome do arquivo. Nesse caso, as cotações de fato importarão, mas é importante perceber que não é o problema do find - é 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 para find .

$ find -type f -exec bash -c "stat -c '%F' '{}'" sh \;                                                                                                                 
regular empty file
regular empty file
regular empty file
    
por Sergiy Kolodyazhnyy 31.10.2017 / 06:53