Verwenden von Konnektoren nach dem Befehl find

10

Ich möchte, dass meine Bash "gefunden" nur druckt, wenn etwas gefunden wird, indem ich den Befehl find verwende. Aber die Verwendung von && hilft nicht: Selbst wenn nichts gefunden wird, werde ich "gefunden" gedruckt. Beispiel:

$ 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
quelle

Antworten:

18

Sie können findsich drucken lassen found:

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

Das -quitwird find nach dem ersten Spiel beendet , wird also foundhöchstens einmal gedruckt.

In einem ähnlichen Thread unter Unix und Linux ( Make Find Fail, wenn nichts gefunden wurde ) habe ich grep -qzeinen Exit-Status ungleich Null zurückgegeben, wenn findnichts gefunden wurde:

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

Mit denen Sie zusammengesetzte Befehle erstellen können, indem Sie &&oder verwenden if:

find /some/path -print0 -quit | grep -qz . && echo found
muru
quelle
Ich musste diese Weile anstarren. /some/pathsagt find, wo man anfangen soll zu suchen, aber nichts sagt ihm, wonach er suchen soll. Gleiches gilt für Ihre verknüpfte Antwort. Was für mich funktioniert, ist find /some/path -name xac -print0 -quit | grep -qz . && echo found. Habe ich etwas verpasst?
Joe
@ Joe was hier zählt ist das -print0 -quit. Was Sie davor setzen, hängt davon ab, was Sie finden möchten. Ich habe beschlossen, das hier wegzulassen.
Muru
13

Die Antwort von muru ist angemessen und gut geeignet für Fälle, in denen wir etwas drucken möchten, wenn eine Datei gefunden wird. Für den allgemeinen Fall, wenn wir einen externen Befehl ausführen möchten, z. B. echokönnten wir -execflag verwenden.

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

Der {}Teil übergibt den Dateinamen an den Befehl zwischen -execund \;als Argumente. Beachten Sie das \Vorherige ;- es verhindert, dass die Shell es falsch interpretiert. ; Im Semikolon zum Schließen der Shell bedeutet das Ende des Befehls. Wenn es jedoch mit einem Schrägstrich versehen wird, behandelt die Shell es als Literall-Text, der an den findBefehl übergeben wird, und um den Befehl zu finden, dient es als -execArgument für das Schließen des Flags.


Für die Erstellung von Bedingungen dieser if found do this; else do thatArt könnten wir Befehlssubstitution $()und testBefehl (aka [) verwenden:

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

Adressierung von Dans Kommentar

Dan fragte in den Kommentaren :

Wäre das Echo "Ich habe {} gefunden" nicht besser als das Echo "Ich habe gefunden" {}? Vielleicht ist es für Echo in Ordnung, aber wenn jemand den Befehl kopiert und das Echo durch einen anderen Befehl ersetzt, hat er möglicherweise ein Problem

Lassen Sie uns zuerst das Problem verstehen. Normalerweise gibt es in Shells das Konzept der Wortteilung, was bedeutet, dass nicht zitierte Variablen und Positionsparameter erweitert und als separate Elemente behandelt werden. Wenn Sie Variable Zum Beispiel haben varund es enthält hello worldText, wenn Sie tun , touch $vardie Schale wird es brechen in zwei separate Elemente hellound worldund touchwird das verstehen , als ob Sie versuchen , zwei separate Dateien zu erstellen; Wenn Sie dies tun touch "$var", wird die Shell hello worldals eine Einheit behandelt und touchnur eine Datei erstellt. Dies ist wichtig zu verstehen, dass dies nur aufgrund der Funktionsweise von Muscheln geschieht.

Im Gegensatz dazu findleidet es nicht unter einem solchen Verhalten, da Befehle von findselbst verarbeitet und per execvp()Systemaufruf ausgeführt werden , sodass keine Shell beteiligt ist. Während geschweifte Klammern in Muscheln eine besondere Bedeutung haben, weil sie in der Mitte des findBefehls und nicht am Anfang erscheinen, haben sie in diesem Fall keine besondere Bedeutung für Muscheln. Hier ist ein Beispiel. Lassen Sie uns ein paar schwierige Dateinamen erstellen und versuchen, sie als Argument an den statBefehl zu übergeben.

$ 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

Wie Sie sehen können, werden statschwierige Dateinamen problemlos verwendet. Dies findist einer der Hauptgründe, warum dies für die Verwendung in tragbaren Skripten empfohlen wird. Dies ist besonders nützlich, wenn Sie den Verzeichnisbaum durchlaufen und möglicherweise mit Dateinamen arbeiten möchten, die möglicherweise vorhanden sind Sonderzeichen in ihnen. Daher ist es nicht erforderlich, geschweifte Klammern für Befehle anzugeben, die in ausgeführt werden find.

Es ist eine andere Geschichte, wenn Shell beteiligt wird. Manchmal müssen Sie eine Shell verwenden, um den Dateinamen zu verarbeiten. In diesem Fall ist das Zitieren zwar wichtig, aber es ist wichtig zu erkennen, dass es nicht das Problem von find ist - es ist die Shell, die die Wortteilung durchführt.

$ 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

Wenn wir also innerhalb der Shell zitieren , wird es funktionieren. Aber auch das ist wichtig für Shell, nicht find.

$ find -type f -exec bash -c "stat -c '%F' '{}'" sh \;                                                                                                                 
regular empty file
regular empty file
regular empty file
Sergiy Kolodyazhnyy
quelle
Wäre nicht echo "I found {}"besser als echo "I found " {}? Vielleicht ist es für Echo in Ordnung, aber wenn jemand den Befehl kopiert und das Echo durch einen anderen Befehl ersetzt, hat er möglicherweise ein Problem.
Dan
@Dan war das Thema zu lang, um es in den Kommentaren zu diskutieren, also habe ich meine Antwort bearbeitet. Bitte sehen Sie es
Sergiy Kolodyazhnyy
1
Vielen Dank, dass ich endlich verstanden habe, warum dieses Semikolon vorhanden sein musste. Auch eine gute Erklärung für das Zitieren.
Joe
1
Ich hatte nicht so viele Details als Antwort auf meinen Kommentar erwartet. Ich schätze diese Erklärung sehr, danke!
Dan