¿Cómo probar si existe una cadena en el archivo con Bash?
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.
grep -Fxq "$FILENAME" my_list.txt
El estado de salida es 0 (verdadero) si se encontró el nombre, 1 (falso) en caso contrario, 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 de manual paragrep
:
grep [options] PATTERN [FILE...]
-F
,--fixed-strings
Interprete PATRÓN como una lista de cadenas fijas, separadas por nuevas líneas, cualquiera de las cuales debe coincidir.
-x
,--line-regexp
Seleccione sólo aquellas coincidencias que coincidan exactamente con toda la línea.
-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
-s
o--no-messages
.
Manejo de errores
Como se señaló 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, deberá omitir la -q
opción y detectar errores según el estado de salida:
Normalmente, el estado de salida es 0 si se encuentran las líneas seleccionadas y 1 en caso contrario. Pero el estado de salida es 2 si ocurrió un error, a menos que se use la opción
-q
o y se encuentre una línea seleccionada. Tenga en cuenta, sin embargo, que POSIX sólo exige, para programas como , y , 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 igualdad estricta con 2.--quiet
--silent
grep
cmp
diff
Para suprimir la salida normal de grep
, puede redirigirla a /dev/null
. Tenga en cuenta que el error estándar no está dirigido, por lo que cualquier mensaje de error que grep
pueda imprimirse terminará en la consola como probablemente desee.
Para manejar los tres casos, podemos usar una case
declaració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
Respecto a la siguiente solución:
grep -Fxq "$FILENAME" my_list.txt
En caso de que te preguntes (como yo) qué -Fxq
significa en inglés sencillo:
F
: Afecta cómo se interpreta PATTERN (cadena fija en lugar de una expresión regular)x
: Coincidir con toda la líneaq
: 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.)
Tres métodos en mi mente:
1) Prueba breve para un nombre en una ruta (no estoy seguro de que este sea su caso)
ls -a "path" | grep "name"
2) Prueba breve para una cadena en un archivo
grep -R "string" "filepath"
3) Script bash más largo que usa expresiones regulares:
#!/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.
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 aparece la cadena en el archivo.