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


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

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

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.


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.


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.


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


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  

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  

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


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



0
grep -Fxq "String to be found" | ls -a
  • grep will te ayuda a verificar el contenido
  • Enumerará todos los archivos

@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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.