Usar conectores después del comando find

10

Quiero que mi bash imprima 'encontrado' solo si se encuentra algo, usando el comando find. Pero usar && no ayuda: incluso si no encuentro nada, me imprimen 'encontrado'. Ejemplo:

$ 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
Josef Klimuk
fuente

Respuestas:

18

Puedes hacerte findimprimir found:

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

Se -quitcerrará find después de la primera coincidencia , por foundlo que solo se imprime como máximo una vez.

En un hilo similar en Unix y Linux ( hacer que find falle cuando no se encontró nada ), solía grep -qzdevolver un estado de salida distinto de cero si findno encontraba nada:

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

Que puedes usar para construir comandos compuestos usando &&o if:

find /some/path -print0 -quit | grep -qz . && echo found
muru
fuente
Tuve que mirar esto por un rato. /some/pathle dice a encontrar dónde comenzar a buscar, pero nada le dice qué buscar. Lo mismo en tu respuesta vinculada. Lo que funciona para mí es find /some/path -name xac -print0 -quit | grep -qz . && echo found. ¿Me he perdido algo?
Joe
@Joe lo que importa aquí es el -print0 -quit. Lo que pones antes de eso depende de lo que quieras encontrar. Elegí omitir eso aquí.
muru
13

La respuesta de muru es apropiada y adecuada para casos en los que queremos imprimir algo si se encuentra el archivo. Para el caso general cuando queremos ejecutar comandos externos, como echo, podríamos usar -execflag.

$ find . -name 'xac' -exec echo "I found " {} \; -quit             
I found  ./xac

La {}parte pasa el nombre de archivo al comando entre -execy \;como argumentos. Tenga en cuenta lo \anterior ;: evita que el shell lo malinterprete ; en el punto y coma que cierra el punto y coma significa el final del comando, pero cuando se escapa con una barra oblicua, el shell lo tratará como un texto literal que se pasará al findcomando y para encontrar el comando sirve como -execargumento de cierre .


Para construir condicionales del if found do this; else do thattipo, podríamos hacer uso de la substición de comando $()y el testcomando (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

Abordar el comentario de Dan

Dan en los comentarios preguntó:

¿No sería mejor "echo he encontrado {}" que echo "he encontrado" {}? Tal vez para echo está bien, pero si alguien copia el comando y reemplaza echo con otro comando, puede tener un problema

Vamos a entender el problema primero. Por lo general, en los shells hay un concepto de división de palabras, lo que significa que las variables no citadas y los parámetros posicionales se expandirán y tratarán como elementos separados. Por ejemplo, si usted tiene la variable vary contiene hello worldtexto, cuando lo hace touch $varel shell dividirlo en dos artículos separados helloy worldy touchva a entender que, como si estuviera tratando de crear 2 archivos separados; Si lo hace touch "$var", Shell lo tratará hello worldcomo una unidad y touchcreará un solo archivo. Esto es importante para entender que esto sucede solo debido a cómo funcionan las conchas.

Por el contrario, findno sufre ese comportamiento, ya que los comandos se procesan por findsí mismos y se ejecutan mediante una execvp()llamada al sistema, por lo que no hay shell involucrado. Si bien las llaves tienen un significado especial en los shells, porque aparecen en el medio del findcomando, y no al principio, no tienen un significado especial para shell en este caso. Aquí hay un ejemplo. Creemos algunos nombres de archivo difíciles e intentemos pasarlos como argumento para statordenar.

$ 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 puede ver, statrecibe nombres de archivo difíciles perfectamente bien find, que es una de las razones principales por las que se recomienda su uso en scripts portátiles, y especialmente útil cuando atraviesa el árbol de directorios y desea hacer algo con nombres de archivo que podrían tener personajes especiales en ellos. Por lo tanto, no es necesario citar llaves para los comandos ejecutados en find.

Es una historia diferente cuando Shell se involucra. A veces necesitas usar un shell para procesar el nombre del archivo. En ese caso, las citas realmente importan, pero es importante darse cuenta de que no es el problema del hallazgo: es el shell el que divide las palabras.

$ 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

Entonces, cuando citamos dentro de Shell , funcionará. Pero de nuevo, eso es importante para Shell, no find.

$ find -type f -exec bash -c "stat -c '%F' '{}'" sh \;                                                                                                                 
regular empty file
regular empty file
regular empty file
Sergiy Kolodyazhnyy
fuente
No echo "I found {}"sería mejor que echo "I found " {}? Tal vez para echo está bien, pero si alguien copia el comando y reemplaza echo con otro comando, pueden tener un problema.
Dan
@Dan, el tema era demasiado largo para discutirlo en los comentarios, así que hice una edición de mi respuesta. Por favor
míralo
1
Gracias por finalmente hacerme entender por qué ese punto y coma necesitaba estar allí. Además, una gran explicación de citas.
Joe
1
No esperaba tantos detalles como respuesta a mi comentario. Aprecio mucho esa explicación, ¡gracias!
Dan