¿Cómo probar si existe una cadena en el archivo con Bash?

337

Tengo un archivo que contiene nombres de directorio:

my_list.txt :

/tmp
/var/tmp

Me gustaría registrar Bash antes de agregar un nombre de directorio si ese nombre ya existe en el archivo.

Toren
fuente
Para encontrar todas las cadenas dentro de un archivo, puede ejecutar grep en el bucle FOR: unix.stackexchange.com/a/462445/43233
Noam Manos

Respuestas:

655
grep -Fxq "$FILENAME" my_list.txt

El estado de salida es 0 (verdadero) si se encontró el nombre, 1 (falso) si no, entonces:

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

Explicación

Aquí están las secciones relevantes de la página del manual paragrep :

grep [options] PATTERN [FILE...]

-F, --fixed-strings

        Interprete PATTERN como una lista de cadenas fijas, separadas por líneas nuevas, cualquiera de las cuales debe coincidir.

-x, --line-regexp

        Seleccione solo aquellas coincidencias que coincidan exactamente con la línea completa.

-q` --quiet`--silent

        Tranquilo; No escriba nada en la salida estándar. Salga inmediatamente con estado cero si se encuentra alguna coincidencia, incluso si se detectó un error. Consulte también la opción -su --no-messages.

Manejo de errores

Como se señala correctamente en los comentarios, el enfoque anterior trata silenciosamente los casos de error como si se encontrara la cadena. Si desea manejar los errores de una manera diferente, tendrá que omitir la -qopción y detectar errores en función del estado de salida:

Normalmente, el estado de salida es 0 si se encuentran líneas seleccionadas y 1 en caso contrario. Pero el estado de salida es 2 si se produjo un error, a menos que el-q o --quieto --silentde opciones se utiliza y se encuentra una línea seleccionada. Tenga en cuenta, sin embargo, que sólo POSIX mandatos, para los programas tales como grep, cmpy diff, que el estado de salida en caso de error sea mayor que 1; Por lo tanto, es aconsejable, en aras de la portabilidad, utilizar una lógica que pruebe esta condición general en lugar de una estricta igualdad con 2.

Para suprimir la salida normal de grep, puede redirigirla a /dev/null. Tenga en cuenta que el error estándar no se dirige, por lo que cualquier mensaje de error que grepse imprima terminará en la consola como probablemente desee.

Para manejar los tres casos, podemos usar una casedeclaración:

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
fuente
2
Si ejecuto este comando desde bash script, ¿cómo atrapar 0 o 1 en una variable?
Toren
66
@Toren Se puede acceder al estado de salida más reciente mediante $?. También puede usar el comando grep junto con la ifinstrucción (como se muestra en la respuesta actualizada).
Shawn Chin
55
Puede usar grep -Fqx "$FILENAME"y no tiene que preocuparse por los caracteres regex en los contenidos variables y no tendrá que usarlos en la cadena de búsqueda.
Pausado hasta nuevo aviso.
44
Un par de notas para las personas que miran esta respuesta: 1) En bash, 0 siempre es verdadero y cualquier otra cosa siempre es falsa 2) Solo use la bandera -x si desea que toda la línea coincida exactamente. Si solo desea saber si su cadena existe en el archivo, déjelo desactivado. Si desea saber si su cadena existe exactamente pero sin coincidir necesariamente con una línea completa (es decir, como una palabra completa), use -w.
Schmick
1
No entiendo, -q / --silent¿se necesita? Falsamente dice "todo bien" golpear incluso si ocurre un error. Si entendí eso correctamente. Parece un concepto defectuoso para este caso.
redanimalwar
90

En cuanto a la siguiente solución:

grep -Fxq "$FILENAME" my_list.txt

En caso de que se pregunte (como lo hice) qué -Fxqsignifica en inglés simple:

  • F: Afecta cómo se interpreta PATTERN (cadena fija en lugar de una expresión regular)
  • x: Unir toda la línea
  • q: Shhhhh ... impresión mínima

Del archivo 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.)
Kuf
fuente
55
-F no afecta el procesamiento del archivo, afecta cómo se interpreta PATTERN. Típicamente, PATTERN se interpreta como una expresión regular, pero con -F se interpretará como una cadena fija.
Adam S
41

Tres métodos en mi mente:

1) Prueba corta para un nombre en una ruta (no estoy seguro de que este sea tu caso)

ls -a "path" | grep "name"


2) Prueba corta para una cadena en un archivo

grep -R "string" "filepath"


3) Script de bash más largo 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

Esto debería ser más rápido si tiene que probar varias cadenas en el contenido de un archivo usando un bucle, por ejemplo, cambiando la expresión regular en cualquier ciclo.

Luca Borrione
fuente
10
¿Por qué son necesarios los espacios antes y después de $ file_contenet?
EminezArtus
Plus 1 para la solución rápida y más generalizable
Wassadamo
19

Manera más simple:

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

Consejo: envíe a /dev/nullsi desea el estado de salida del comando, pero no las salidas.

imwilsonxu
fuente
1
o use -qel mismo que --quiet:)
rogerdpack
de acuerdo en la -qmejor respuesta aquí, y es el cuarto lugar. No hay justicia en este mundo.
tatsu
15

La forma más fácil y sencilla sería:

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 devolverá el recuento de cuántas veces se produce la cadena en el archivo.

Cristiano737
fuente
5

Si entendí tu pregunta correctamente, esto debería hacer lo que necesitas.

  1. puede especificar el directorio que desea agregar a través de la variable $ check
  2. si el directorio ya está en la lista, la salida es "dir ya en la lista"
  3. si el directorio aún no está en la lista, se agrega a my_list.txt

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

lecodesportif
fuente
No necesita probar la salida de grep, solo puede usar grep -qy llamar a grep directamente ifcomo lo hace Thomas en su respuesta. Además, la pregunta no incluía verificar si el directorio existe antes de agregarlo a la lista (después de todo, podría ser una lista de directorios eliminados).
sorigal
Eliminé el script de ejemplo, no agregó nada a la respuesta dada por Thomas.
lecodesportif
3

Si solo desea verificar la existencia de una línea, no necesita crear un archivo. P.ej,

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
fuente
3

Mi versión usando fgrep

  FOUND=`fgrep -c "FOUND" $VALIDATION_FILE`
  if [ $FOUND -eq 0 ]; then
    echo "Not able to find"
  else
    echo "able to find"     
  fi  
Rudy
fuente
No veo la -copción enfgrep --help
Nam G VU
3
grep -E "(string)" /path/to/file || echo "no match found"

La opción -E hace que grep use expresiones regulares

David Okwii
fuente
1

La solución de @ Thomas no funcionó para mí por alguna razón, pero tenía una cadena más larga con caracteres especiales y espacios en blanco, así que simplemente cambié los parámetros de esta manera:

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

Espero que ayude a alguien

Ingrown29
fuente
0

Una solución sin grep, funciona para mí:

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

basado en: https://stackoverflow.com/a/229606/3306354

AndrewD
fuente
1
Utiliza demasiada memoria en caso de que el archivo sea grande. grep -qdescrito en la respuesta aceptada es el enfoque más eficiente.
codeforester
0
grep -Fxq "String to be found" | ls -a
  • grep will te ayuda a verificar el contenido
  • Enumerará todos los archivos
Shinoy Shaji
fuente
@ThomWiggers Intenté lo mismo y funcionó para mí.
Shinoy Shaji
-1
if grep -q "$Filename$" my_list.txt
   then
     echo "exist"
else 
     echo "not exist"
fi
Triángulo
fuente