Wie teste ich, ob eine Zeichenfolge in einer Datei mit Bash vorhanden ist?

337

Ich habe eine Datei, die Verzeichnisnamen enthält:

my_list.txt ::

/tmp
/var/tmp

Ich möchte Bash einchecken, bevor ich einen Verzeichnisnamen hinzufüge, wenn dieser Name bereits in der Datei vorhanden ist.

Toren
quelle
Um alle Zeichenfolgen in einer Datei zu finden, können Sie grep in der FOR-Schleife ausführen
Noam Manos

Antworten:

654
grep -Fxq "$FILENAME" my_list.txt

Der Exit-Status ist 0 (true), wenn der Name gefunden wurde, 1 (false), wenn nicht, also:

if grep -Fxq "$FILENAME" my_list.txt
then
    # code if found
else
    # code if not found
fi

Erläuterung

Hier sind die relevanten Abschnitte der Manpage fürgrep :

grep [options] PATTERN [FILE...]

-F, --fixed-strings

        Interpretieren Sie PATTERN als eine Liste fester Zeichenfolgen, die durch Zeilenumbrüche getrennt sind und mit denen alle übereinstimmen sollen.

-x, --line-regexp

        Wählen Sie nur die Übereinstimmungen aus, die genau mit der gesamten Zeile übereinstimmen.

-q, --quiet,--silent

        Ruhig; Schreiben Sie nichts in die Standardausgabe. Beenden Sie das Programm sofort mit dem Status Null, wenn eine Übereinstimmung gefunden wird, auch wenn ein Fehler festgestellt wurde. Siehe auch die Option -soder --no-messages.

Fehlerbehandlung

Wie in den Kommentaren zu Recht ausgeführt, behandelt der obige Ansatz Fehlerfälle stillschweigend so, als ob die Zeichenfolge gefunden worden wäre. Wenn Sie Fehler auf andere Weise behandeln möchten, müssen Sie die -qOption weglassen und Fehler anhand des Beendigungsstatus erkennen:

Normalerweise ist der Exit-Status 0, wenn ausgewählte Zeilen gefunden werden, andernfalls 1. Der Exit-Status ist jedoch 2, wenn ein Fehler aufgetreten ist, es sei denn, die Option -qoder --quietoder --silentwird verwendet und eine ausgewählte Zeile wird gefunden. Beachten Sie jedoch, dass POSIX nur Mandate, für Programme wie grep, cmpund diff, dass der Exit - Status im Fehlerfall größer als 1 ist ; Aus Gründen der Portabilität ist es daher ratsam, eine Logik zu verwenden, die diese allgemeine Bedingung prüft, anstatt strikt mit 2 gleich zu sein.

Um die normale Ausgabe von zu unterdrücken grep, können Sie sie umleiten /dev/null. Beachten Sie, dass der Standardfehler ungerichtet bleibt, sodass alle grepmöglicherweise ausgegebenen Fehlermeldungen auf der Konsole angezeigt werden, wie Sie es wahrscheinlich möchten.

Um die drei Fälle zu behandeln, können wir eine caseAnweisung verwenden:

case `grep -Fx "$FILENAME" "$LIST" >/dev/null; echo $?` in
  0)
    # code if found
    ;;
  1)
    # code if not found
    ;;
  *)
    # code if an error occurred
    ;;
esac
Thomas
quelle
2
Wenn ich diesen Befehl über ein Bash-Skript ausführe, wie kann ich 0 oder 1 in eine Variable einfangen?
Toren
6
@Toren Auf den neuesten Exit-Status kann mit zugegriffen werden $?. Sie können auch den Befehl grep neben der ifAnweisung verwenden (wie in der aktualisierten Antwort gezeigt).
Shawn Chin
5
Sie können grep -Fqx "$FILENAME"Regex-Zeichen im variablen Inhalt verwenden und müssen sich keine Gedanken darüber machen, und Sie müssen sie nicht in der Suchzeichenfolge verwenden.
Bis auf weiteres angehalten.
4
Ein paar Anmerkungen für Leute, die sich diese Antwort ansehen: 1) In bash ist 0 immer wahr und alles andere ist immer falsch. 2) Verwenden Sie das Flag -x nur, wenn die gesamte Zeile genau übereinstimmen soll. Wenn Sie nur herausfinden möchten, ob Ihre Zeichenfolge überhaupt in der Datei vorhanden ist, lassen Sie dies aus. Wenn Sie herausfinden möchten, ob Ihre Zeichenfolge genau vorhanden ist, aber nicht unbedingt mit einer ganzen Zeile übereinstimmt (dh als ganzes Wort), verwenden Sie -w.
Schmick
1
Ich verstehe nicht, ob -q / --silentes gebraucht wird? Es sagt fälschlicherweise "alles gut", um zu schlagen, selbst wenn ein Fehler auftritt. Wenn ich das richtig verstanden habe. Scheint ein fehlerhaftes Konzept für diesen Fall.
Redanimalwar
90

In Bezug auf die folgende Lösung:

grep -Fxq "$FILENAME" my_list.txt

Falls Sie sich fragen (wie ich), was -Fxqim Klartext bedeutet:

  • F: Beeinflusst die Interpretation von PATTERN (feste Zeichenfolge anstelle eines regulären Ausdrucks)
  • x: Ganze Linie abgleichen
  • q: Shhhhh ... minimaler Druck

Aus der Man-Datei:

-F, --fixed-strings
    Interpret  PATTERN  as  a  list of fixed strings, separated by newlines, any of which is to be matched.
    (-F is specified by POSIX.)
-x, --line-regexp
    Select only those matches that exactly match the whole line.  (-x is specified by POSIX.)
-q, --quiet, --silent
    Quiet; do not write anything to standard output.  Exit immediately with zero status  if  any  match  is
          found,  even  if  an error was detected.  Also see the -s or --no-messages option.  (-q is specified by
          POSIX.)
Kuf
quelle
5
-F hat keinen Einfluss auf die Dateiverarbeitung, sondern auf die Interpretation von PATTERN. Normalerweise wird PATTERN als regulärer Ausdruck interpretiert, aber mit -F wird es als fester String interpretiert.
Adam S
41

Drei Methoden in meinem Kopf:

1) Kurztest für einen Namen in einem Pfad (ich bin nicht sicher, ob dies Ihr Fall sein könnte)

ls -a "path" | grep "name"


2) Kurztest für eine Zeichenfolge in einer Datei

grep -R "string" "filepath"


3) Längeres Bash-Skript mit Regex:

#!/bin/bash

declare file="content.txt"
declare regex="\s+string\s+"

declare file_content=$( cat "${file}" )
if [[ " $file_content " =~ $regex ]] # please note the space before and after the file content
    then
        echo "found"
    else
        echo "not found"
fi

exit

Dies sollte schneller sein, wenn Sie mehrere Zeichenfolgen für einen Dateiinhalt mithilfe einer Schleife testen müssen , z. B. um den regulären Ausdruck an einem beliebigen Cicle zu ändern.

Luca Borrione
quelle
10
Warum sind die Leerzeichen vor und nach dem $ file_contenet erforderlich?
EminezArtus
Plus 1 für die schnelle Lösung und eine allgemeinere
Wassadamo
19

Einfacherer Weg:

if grep "$filename" my_list.txt > /dev/null
then
   ... found
else
   ... not found
fi

Tipp: Senden Sie an, /dev/nullwenn Sie den Beendigungsstatus des Befehls, jedoch keine Ausgaben wünschen.

imwilsonxu
quelle
1
oder verwenden Sie -qdie gleiche wie --quiet:)
Rogerdpack
stimme -qhier auch der besten Antwort zu und ist Vierter. keine Gerechtigkeit in dieser Welt.
Tatsu
14

Der einfachste und einfachste Weg wäre:

isInFile=$(cat file.txt | grep -c "string")


if [ $isInFile -eq 0 ]; then
   #string not contained in file
else
   #string is in file at least once
fi

grep -c gibt zurück, wie oft die Zeichenfolge in der Datei vorkommt.

Christian737
quelle
5

Wenn ich Ihre Frage richtig verstanden habe, sollte dies das tun, was Sie brauchen.

  1. Sie können das Verzeichnis angeben, das Sie über die Variable $ check hinzufügen möchten
  2. Wenn das Verzeichnis bereits in der Liste enthalten ist, lautet die Ausgabe "Verzeichnis bereits aufgelistet".
  3. Wenn das Verzeichnis noch nicht in der Liste enthalten ist, wird es an my_list.txt angehängt

In einer Zeile :check="/tmp/newdirectory"; [[ -n $(grep "^$check\$" my_list.txt) ]] && echo "dir already listed" || echo "$check" >> my_list.txt

lecodesportif
quelle
Sie müssen die Ausgabe von grep nicht testen, sondern können grep einfach grep -qdirekt von ifThomas aus verwenden und aufrufen, wie es Thomas in seiner Antwort tut. Außerdem wurde nicht geprüft, ob das Verzeichnis vorhanden ist, bevor es zur Liste hinzugefügt wurde (es könnte sich schließlich um eine Liste gelöschter Verzeichnisse handeln).
Sorpigal
Ich habe das Beispielskript entfernt, es hat der Antwort von Thomas nichts hinzugefügt.
Lecodesportif
3

Wenn Sie nur das Vorhandensein einer Zeile überprüfen möchten, müssen Sie keine Datei erstellen. Z.B,

if grep -xq "LINE_TO_BE_MATCHED" FILE_TO_LOOK_IN ; then
  # code for if it exists
else
  # code for if it does not exist
fi  
Gordon
quelle
3

Meine Version mit fgrep

  FOUND=`fgrep -c "FOUND" $VALIDATION_FILE`
  if [ $FOUND -eq 0 ]; then
    echo "Not able to find"
  else
    echo "able to find"     
  fi  
Rudy
quelle
Ich sehe keine -cOption infgrep --help
Nam G VU
3
grep -E "(string)" /path/to/file || echo "no match found"

Mit der Option -E verwendet grep reguläre Ausdrücke

David Okwii
quelle
1

Die Lösung von @ Thomas hat aus irgendeinem Grund bei mir nicht funktioniert, aber ich hatte eine längere Zeichenfolge mit Sonderzeichen und Leerzeichen, sodass ich die Parameter wie folgt geändert habe:

if grep -Fxq 'string you want to find' "/path/to/file"; then
    echo "Found"
else
    echo "Not found"
fi

Hoffe es hilft jemandem

Eingewachsen29
quelle
0

Eine grep-freie Lösung funktioniert für mich:

MY_LIST=$( cat /path/to/my_list.txt )



if [[ "${MY_LIST}" == *"${NEW_DIRECTORY_NAME}"* ]]; then
  echo "It's there!"
else
echo "its not there"
fi

basierend auf: https://stackoverflow.com/a/229606/3306354

AndrewD
quelle
1
Verbraucht zu viel Speicher, falls die Datei groß ist. grep -qIn der akzeptierten Antwort beschrieben ist der effizienteste Ansatz.
Codeforester
0
grep -Fxq "String to be found" | ls -a
  • grep wird Ihnen helfen, Inhalte zu überprüfen
  • ls listet alle Dateien auf
Shinoy Shaji
quelle
Ich glaube nicht, dass lsStandardeingaben akzeptiert werden?
Thom Wiggers
@ThomWiggers Ich habe das gleiche versucht und es hat bei mir funktioniert.
Shinoy Shaji
-1
if grep -q "$Filename$" my_list.txt
   then
     echo "exist"
else 
     echo "not exist"
fi
Dreieck
quelle