Come verificare se la stringa esiste nel file con Bash?


337

Ho un file che contiene i nomi di directory:

my_list.txt :

/tmp
/var/tmp

Vorrei controllare Bash prima di aggiungere un nome di directory se quel nome esiste già nel file.


Per trovare tutte le stringhe all'interno di un file, puoi eseguire grep nel ciclo FOR: unix.stackexchange.com/a/462445/43233
Noam Manos

Risposte:


655
grep -Fxq "$FILENAME" my_list.txt

Lo stato di uscita è 0 (vero) se il nome è stato trovato, 1 (falso) in caso contrario, quindi:

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

Spiegazione

Ecco le sezioni rilevanti della pagina man pergrep :

grep [options] PATTERN [FILE...]

-F, --fixed-strings

        Interpreta PATTERN come un elenco di stringhe fisse, separate da newline, ognuna delle quali deve essere abbinata.

-x, --line-regexp

        Seleziona solo quelle corrispondenze che corrispondono esattamente all'intera riga.

-q, --quiet,--silent

        Silenzioso; non scrivere nulla sullo standard output. Esci immediatamente con stato zero se viene rilevata una corrispondenza, anche se è stato rilevato un errore. Vedi anche l' opzione -so --no-messages.

Gestione degli errori

Come giustamente sottolineato nei commenti, l'approccio sopra tratta silenziosamente i casi di errore come se fosse trovata la stringa. Se desideri gestire gli errori in modo diverso, dovrai omettere l' -qopzione e rilevare gli errori in base allo stato di uscita:

Normalmente, lo stato di uscita è 0 se vengono trovate le linee selezionate e 1 altrimenti. Ma lo stato di uscita è 2 se si è verificato un errore, a meno che non venga utilizzata l'opzione -qo --quieto --silente venga trovata una linea selezionata. Si noti, tuttavia, che POSIX mandati solo, per programmi come grep, cmpe diffche lo stato di uscita in caso di errore sia maggiore di 1; è quindi consigliabile, per motivi di portabilità, utilizzare la logica che verifica questa condizione generale anziché la rigorosa uguaglianza con 2.

Per sopprimere l'output normale da grep, è possibile reindirizzarlo a /dev/null. Si noti che l'errore standard rimane non indirizzato, quindi tutti i messaggi di errore che greppotrebbero essere stampati finiranno sulla console come si vorrebbe.

Per gestire i tre casi, possiamo usare caseun'istruzione:

case `grep -Fx "$FILENAME" "$LIST" >/dev/null; echo $?` in
  0)
    # code if found
    ;;
  1)
    # code if not found
    ;;
  *)
    # code if an error occurred
    ;;
esac

2
Se eseguo questo comando dallo script bash come catturare 0 o 1 in una variabile?
Toren,

6
@Toren È possibile accedere allo stato di uscita più recente utilizzando $?. puoi anche usare il comando grep accanto ifall'istruzione (come mostrato nella risposta aggiornata).
Shawn Chin,

5
Puoi usare grep -Fqx "$FILENAME"e non devi preoccuparti dei caratteri regex nei contenuti delle variabili e non dovrai usarli nella stringa di ricerca.
In pausa fino a ulteriore avviso.

4
Un paio di note per chi guarda questa risposta: 1) In bash, 0 è sempre vero e tutto il resto è sempre falso 2) Usa il flag -x solo se vuoi che l'intera riga corrisponda esattamente. Se vuoi solo scoprire se la tua stringa esiste nel file, lasciala fuori. Se vuoi scoprire se la tua stringa esiste esattamente ma senza necessariamente corrispondere a un'intera riga (cioè, come una parola intera), usa -w.
Schmick

1
Non capisco il -q / --silentnecessario? Dice falsamente "tutto bene" per colpire anche se si verifica un errore. Se ho capito bene. Sembra un concetto imperfetto per questo caso.
redanimalwar,

90

Per quanto riguarda la seguente soluzione:

grep -Fxq "$FILENAME" my_list.txt

Nel caso ti stia chiedendo (come ho fatto io) cosa -Fxqsignifica in parole povere:

  • F: Influisce sull'interpretazione di PATTERN (stringa fissa anziché regex)
  • x: Abbina l'intera riga
  • q: Shhhhh ... stampa minima

Dal file man:

-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.)

5
-F non influisce sull'elaborazione del file, influisce sull'interpretazione di PATTERN. Tipicamente, PATTERN viene interpretato come regex, ma con -F verrà interpretato come una stringa fissa.
Adam S

41

Tre metodi nella mia mente:

1) Breve test per un nome in un percorso (non sono sicuro che questo potrebbe essere il tuo caso)

ls -a "path" | grep "name"


2) Breve test per una stringa in un file

grep -R "string" "filepath"


3) Script bash più lungo usando 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

Questo dovrebbe essere più veloce se devi testare più stringhe su un contenuto di file usando un loop, ad esempio cambiando la regex in qualsiasi ciclo.


10
Perché gli spazi sono necessari prima e dopo $ file_contenet?
EminezArtus,

Più 1 per la soluzione rapida e una più generalizzabile
Wassadamo,

19

Modo più semplice:

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

Suggerimento: invia a /dev/nullse si desidera lo stato di uscita del comando, ma non gli output.


1
o utilizzare lo -qstesso di --quiet:)
rogerdpack

sono d'accordo -qanche sulla migliore risposta qui, ed è il quarto posto. nessuna giustizia in questo mondo.
Tatsu,

15

Il modo più semplice e semplice sarebbe:

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 restituirà il conteggio di quante volte si verifica la stringa nel file.


5

Se ho capito correttamente la tua domanda, questo dovrebbe fare quello che ti serve.

  1. puoi specificare la directory che desideri aggiungere attraverso la variabile $ check
  2. se la directory è già nell'elenco, l'output è "dir già elencato"
  3. se la directory non è ancora nell'elenco, viene aggiunta a my_list.txt

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


Non è necessario testare l'output di grep, puoi semplicemente usare grep -qe chiamare grep direttamente da ifcome Thomas fa nella sua risposta. Inoltre, la domanda non includeva il controllo dell'esistenza della directory prima di aggiungerla all'elenco (potrebbe essere un elenco di directory eliminate, dopo tutto).
sorpigal

Ho rimosso lo script di esempio, non ha aggiunto nulla alla risposta data da Thomas.
lecodesportif,

3

Se vuoi solo verificare l'esistenza di una riga, non è necessario creare un file. Per esempio,

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  

3

La mia versione usando fgrep

  FOUND=`fgrep -c "FOUND" $VALIDATION_FILE`
  if [ $FOUND -eq 0 ]; then
    echo "Not able to find"
  else
    echo "able to find"     
  fi  

Non vedo l' -copzione infgrep --help
Nam G VU

3
grep -E "(string)" /path/to/file || echo "no match found"

-L'opzione fa in modo che grep usi espressioni regolari


1

La soluzione di @ Thomas non ha funzionato per me per qualche motivo, ma avevo una stringa più lunga con caratteri speciali e spazi bianchi, quindi ho cambiato i parametri in questo modo:

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

Spero che aiuti qualcuno



0
grep -Fxq "String to be found" | ls -a
  • grep ti aiuterà a controllare i contenuti
  • Elencherà tutti i file

@ThomWiggers Ho provato lo stesso e ha funzionato per me.
Shinoy Shaji,

-1
if grep -q "$Filename$" my_list.txt
   then
     echo "exist"
else 
     echo "not exist"
fi
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.