files - grep regex example
Bash: One-liner para salir con el estado opuesto de un comando grep? (10)
¿Cómo puedo reducir el siguiente script de bash?
grep -P "STATUS: (?!Perfect)" recess.txt && exit 1
exit 0
Parece que debería poder hacerlo con un solo comando, pero tengo un total de 3 aquí.
Mi programa debe:
- Leer recess.txt
- Salir 1 (o no cero) si contiene una línea con "STATUS:" de NOT "Perfect"
- Salga de 0 si no existe tal línea (es decir, todas las "ESTADO:" las líneas son "Perfectas")
El premio de la respuesta va a la escritura más apretada. ¡Gracias!
Archivos de ejemplo
El programa debe tener estado de salida 0 para este archivo:
FILE: styles.css
STATUS: Perfect!
FILE: contour-styles.css
STATUS: Perfect!
El programa debe tener el estado de salida 1 (o distinto de cero) para este archivo:
FILE: styles.css
STATUS: Perfect!
FILE: contour-styles.css
STATUS: Busted
FAILURES: 1 failure
Id''s should not be styled
1. #asdf
El problema con las respuestas de grep es que si el archivo está vacío, también obtendrá una respuesta limpia, como si el archivo tuviera un resultado perfecto. Así que personalmente renuncié a grep por esto y usé awk.
awk ''BEGIN{ef=2}; /STATUS: Perfect/{ ef=0;}; /STATUS: Busted/{ print;eff=3;}; END{exit (ef+eff)}'' a.txt ; echo $?
This has exit status:
0 : Perfect and !Busted
2 : !Perfect and Busted
3 : Perfect and Busted
5 : !Perfect and !Busted
En realidad no es necesario utilizar exit
en absoluto. Lógicamente, no importa cuál sea el resultado de grep, su script se cerrará de todos modos. Dado que el valor de salida de un script de shell es el código de salida del último comando que se ejecutó, simplemente ejecute grep
como el último comando, usando la opción -v
para invertir la coincidencia y corregir el valor de salida. Por lo tanto, su script puede reducirse a solo:
grep -vqP "STATUS: (?!Perfect)" recess.txt
EDITAR:
Lo sentimos, lo anterior no funciona cuando hay otros tipos de líneas en el archivo. Sin embargo, en el interés de evitar ejecutar múltiples comandos, awk
puede lograr todo el shebang con algo como:
awk ''/STATUS: / && ! /Perfect/{exit 1}'' recess.txt
Si decides que quieres la salida que grep habría proporcionado, puedes hacer:
awk ''/^STATUS: / && ! /Perfect/{print;ec=1} END{exit ec}'' recess.txt
Me encontré con esto, necesitando una onlyif
declaración para Puppet. Como tal, la solución de bash de Tgr no funcionaría, y no quería expandir la complejidad como en la respuesta de Christopher Neylan .
Terminé usando una versión inspirada en la respuesta de Henri Schomäcker , pero notablemente simplificada:
grep -P "STATUS: (?!Perfect)" recess.txt; test $? -eq 1
Lo que simplemente invierte el código de salida, devolviendo el éxito solo si no se encuentra el texto:
- Si grep devuelve 0 (coincidencia encontrada), la
test 0 -eq 1
devolverá 1. - Si grep devuelve 1 (no se encontró ninguna coincidencia), la
test 1 -eq 1
devolverá 0. - Si grep devuelve 2 (error), la
test 2 -eq 1
devolverá 1.
Que es exactamente lo que quería: devolver 0 si no se encuentra una coincidencia, y 1 de lo contrario.
Para que funcione con set -e
en un sub-shell con (
y )
:
$ cat test.sh
#!/bin/bash
set -ex
(! ls /tmp/dne)
echo Success
$ ./test.sh
+ ls /tmp/dne
ls: cannot access /tmp/dne: No such file or directory
+ echo Success
Success
$ mkdir /tmp/dne
$ ./test.sh
+ ls /tmp/dne
$
Si alguien llega aquí buscando una manipulación de código de retorno de bash:
(grep <search> <files> || exit 0 && exit 123;)
esto devolverá 0
(éxito) cuando grep no encuentre nada, y devolverá 123
(error) cuando lo haga. Los paréntesis están en caso de que alguien lo pruebe como está en el indicador de shell. con paréntesis no se desconectará en la salida, sino que simplemente saldrá de la subshell con el mismo código de error.
Lo uso para una rápida comprobación de sintaxis en archivos js:
find src/js/ -name /*js -exec node /{/} /; 2>&1 | grep -B 5 SyntaxError || exit 0 && exit 1;
Solo negate el valor de retorno.
! grep -P "STATUS: (?!Perfect)" recess.txt
Solo negar el valor de retorno no funciona en un contexto set -e. Pero puedes hacer:
! grep -P "STATUS: (?!Perfect)" recess.txt || false
También necesitaba tal solución para escribir títeres solo en declaraciones y se me ocurrió el siguiente comando:
/bin/grep --quiet ''root: [email protected]'' /etc/aliases; if [ $? -eq 0 ]; then test 1 -eq 2; else test 1 -eq 1; fi;
Usa el especial ?
variable
grep -P "STATUS: (?!Perfect)" recess.txt
exit $((1-$?))
(Pero tenga en cuenta que grep
también puede devolver 2, por lo que no está claro qué desea que ocurra en tales casos).
[ $(grep -c -P "STATUS: (?!Perfect)" recess.txt) -eq 0 ]