Kann grep true / false zurückgeben oder gibt es alternative Methoden?

130

Als Teil dieses Skripts muss ich überprüfen können, ob das erste angegebene Argument mit dem ersten Wort der Datei übereinstimmt. Wenn dies der Fall ist, beenden Sie das Programm mit einer Fehlermeldung. Wenn dies nicht der Fall ist, hängen Sie die Argumente an die Datei an. Ich verstehe, wie man die ifAnweisung schreibt , aber nicht, wie man sie grepin einem Skript verwendet. Ich verstehe, das grepwird ungefähr so ​​aussehen

grep ^$1 schemas.txt

Ich denke, das sollte viel einfacher sein, als ich es mache.

Ich erhalte die Fehlermeldung "zu viele Argumente" if. Ich habe den Zwischenraum entfernt grep -qund dann einen fehlerhaften Binäroperator erwartet bekommen.

if [ grep -q ^$1 schemas.txt ]
then
        echo "Schema already exists. Please try again"
        exit 1
else
        echo "$@" >> schemas.txt
fi
Lauren
quelle
1
Verliere das [... ]und es wird funktionieren. Obwohl Sie wahrscheinlich Ihr Muster zitieren möchten:if grep -q "^$1" schemas.txt; then …
Derobert
Einzeilige Lösung mit Bashs "Group Command" -Funktion: stackoverflow.com/questions/6550484/…
Trevor Boyd Smith

Antworten:

186

grepGibt einen anderen Exit-Code zurück, wenn etwas (Null) gefunden wurde, oder wenn nichts gefunden wurde (nicht Null). In einer ifAnweisung wird ein Exit-Code ungleich Null auf "true" und ein Exit-Code ungleich Null auf "false" abgebildet. Außerdem hat grep ein -qArgument, um den übereinstimmenden Text nicht auszugeben (sondern nur den Exit-Statuscode zurückzugeben).

So können Sie grep wie folgt verwenden:

if grep -q PATTERN file.txt; then
    echo found
else
    echo not found
fi

Kurz gesagt , wenn Sie so etwas tun if [ -z "$var" ]…, stellt sich heraus, dass [es sich tatsächlich um einen Befehl handelt, den Sie ausführen , genau wie grep. Auf meinem System ist es /usr/bin/[. (Nun, technisch gesehen hat Ihre Shell es wahrscheinlich eingebaut, aber das ist eine Optimierung. Es verhält sich so, als wäre es ein Befehl). Es funktioniert auf die gleiche Weise und [gibt einen Null-Exit-Code für true und einen Nicht-Null-Exit-Code für false zurück. ( testist dasselbe wie [, bis auf das Schließen ])

derobert
quelle
Warum braucht die if-Anweisung keine eckigen Klammern? Ich habe es ohne zu arbeiten, aber verstehe nicht warum. Kann ich es trotzdem ohne die Klammern verschachteln?
Lauren
@Lauren hast du die kurze Notiz verpasst? [Ist nicht Teil der Syntax , wenn, ist es (konzeptuell) ein Befehl , den Sie ausführen, wie grep
Derobert
2
@Lauren Sie verwenden grep nicht in [, Sie verwenden das eine oder andere, je nachdem, welche Bedingung Sie überprüfen möchten. (Sie können jeden Befehl in einem if verwenden, übrigens, wenn Sie nur den Exit-Code überprüfen.)… Nun, ich denke, Sie könnten sich wahrscheinlich einen Grund ausdenken, grep inside [zu verwenden, aber das wäre ein ziemlich kompliziertes Skript und sein keine normale Sache zu tun.
Derobert
3
Zu Ihrer Information, starten Sie ls -l /usr/bin/\[und um man [zu sehen, dass [es sich um ein Programm wie jedes andere handelt, sieht es einfach wie ein syntaktisches Element aus - dies sollte es klar und verständlich machen. (Der Einfachheit halber [ist es auch in Bash, Dash und andere integriert - aber es ist immer noch ein Befehl). versuche es auch type -all [in bash.
cas
1
@AlexanderCska Wenn grep die übereinstimmenden Zeilen drucken soll (z. B. um sie irgendwo weiterzuleiten), lassen Sie die -qOption weg, die grep anweist , leise zu sein (die übereinstimmenden Zeilen nicht zu drucken).
Derobert
48

Eine andere einfache Möglichkeit ist die Verwendung grep -c.

Dieser gibt (nicht als Exit-Code zurück) die Anzahl der Zeilen aus, die mit dem Muster übereinstimmen, also 0, wenn keine Übereinstimmung vorliegt, oder 1 oder mehr, wenn eine Übereinstimmung vorliegt.

Wenn Sie also überprüfen möchten, ob das Muster dreimal oder öfter übereinstimmt, tun Sie Folgendes:

if [ "$(grep -c "^$1" schemas.txt)" -ge 3 ]; then
  ...
amigal
quelle
17
Genauer gesagt, es wird 1 ausgegeben, wenn es nur einmal gefunden wird. Verwenden Sie grep -cim1stattdessen, um 1 unabhängig von der Anzahl der gefundenen Übereinstimmungen auszugeben .
Manatwork
Diese Methode kann auch verwendet werden, um zwischen grep error und grep 'pattern found 0 times' zu unterscheiden. (obwohl nicht mit der genauen if-Anweisung verwendet, denke ich, dass eine Variable erforderlich ist)
Evan Benn
3

Ich weiß, dass ich zu spät dafür bin, aber ich liebe diese kurze Version:

grep -q ^$1 schemas.txt && echo "Schema already exists. Please try again" || echo "$@" >> schemas.txt
Denis Pitzalis
quelle
0

Wenn wir das erste Wort einer Datei abfangen wollen, müssen wir -zwgrep hinzufügen

if grep -qzw "^$1" file
then 
   ... 
else 
   ... 
fi

Ohne -zbekommen wir das erste Wort einer Zeile. Ohne -wbekommen wir teilweise Worte.

Joao
quelle
-2

Wenn Sie es mit eckigen Klammern verwenden möchten, können Sie Folgendes ausführen

if [ `grep -q PATTERN file.txt` ]; then
    echo found
else
    echo not found

Diese Logik funktioniert für alle Befehle. Platzieren Sie Ihre Befehle einfach im Backtick (die Schaltfläche über der Registerkarte oder nach unten auf der Esc-Schaltfläche oder links auf der 1-Schaltfläche).

k_vishwanath
quelle
1
Sie müssten das in Anführungszeichen setzen `grep -q PATTERN file.txt`, andernfalls wird der Operator split + glob angewendet, und dies würde Probleme bei jeder Ausgabe verursachen, die Zeichen $IFSoder Platzhalterzeichen enthält . Im Allgemeinen [ "`cmd`" ]würde true zurückgegeben, wenn cmdmindestens eine nicht leere Zeile auf stdout ausgegeben wird (mit potenziellen Problemen, wenn NUL-Bytes ausgegeben werden). Das heißt, die Shell muss die gesamte Ausgabe im Speicher ablegen und warten, bis sie beendet ist. Die Verwendung von if cmd | grep -q .stattdessen kann in dieser Hinsicht vorzuziehen sein.
Stéphane Chazelas
Dieser Befehl würde überhaupt keinen Sinn ergeben. Der Zweck des -qSchalters ist die Unterdrückung grep der Ausgabe. Sie sagen: Suchen Sie nach PATTERN in der Datei file.txt, unterdrücken Sie alle Ausgaben und setzen Sie den Rückgabestatus entsprechend, ob PATTERN gefunden wurde. Dann ignorieren den Rückgabestatus, nehmen Sie die Befehlsausgabe (die wir leer sein gezwungen), einzelne Wörter aufgespalten und Datei glob Expansion gelten (was ohne Argumente überhaupt), dann führen Sie den [(aka test) Befehl mit genau einem Argument - nämlich , ]- und dann, da dies zu einem Fehler führt, "nicht gefunden". @ StéphaneChazelas, habe ich etwas verpasst?
Wildcard
1
@Wildcard, du hast recht, ich habe das anscheinend übersehen -q. Dieser Kommentar hätte Sinn ergeben [ `grep PATTERN file.txt ` ], wäre aber, wie im Kommentar angedeutet, [ "`grep -n PATTERN file.txt`" ]besser, wenn PATTERN nur mit leeren Zeilen übereinstimmt. Obwohl if grep -q PATTERN file.txtdu es hier natürlich willst.
Stéphane Chazelas