¿Puede grep devolver verdadero / falso o existen métodos alternativos?

130

Como parte de este script, necesito poder verificar si el primer argumento dado coincide con la primera palabra del archivo. Si lo hace, salga con un mensaje de error; si no es así, agregue los argumentos al archivo. Entiendo cómo escribir la ifdeclaración, pero no cómo usarla grepdentro de un script. Entiendo que grepse verá algo así

grep ^$1 schemas.txt

Siento que esto debería ser mucho más fácil de lo que lo estoy haciendo.

Recibo un error "demasiados argumentos" en la ifdeclaración. Me deshice del espacio entre grep -qy luego obtuve un error binario de operador esperado.

if [ grep -q ^$1 schemas.txt ]
then
        echo "Schema already exists. Please try again"
        exit 1
else
        echo "$@" >> schemas.txt
fi
Lauren
fuente
1
Pierde el [... ]y funcionará. Aunque probablemente desee citar su patrón:if grep -q "^$1" schemas.txt; then …
derobert
solución de una línea que utiliza la función "Comando grupal" de Bash: stackoverflow.com/questions/6550484/…
Trevor Boyd Smith

Respuestas:

186

grepdevuelve un código de salida diferente si encuentra algo (cero) frente a si no ha encontrado nada (distinto de cero). En una ifdeclaración, un código de salida cero se asigna a "verdadero" y un código de salida distinto de cero se asigna a falso. Además, grep tiene un -qargumento para no generar el texto coincidente (sino que solo devuelve el código de estado de salida)

Entonces, puedes usar grep así:

if grep -q PATTERN file.txt; then
    echo found
else
    echo not found
fi

Como nota rápida, cuando haces algo así if [ -z "$var" ]…, resulta que en [realidad es un comando que estás ejecutando, al igual que grep. En mi sistema, es /usr/bin/[. (Bueno, técnicamente, su shell probablemente lo tiene incorporado, pero eso es una optimización. Se comporta como si fuera un comando). Funciona de la misma manera, [devuelve un código de salida cero para verdadero, un código de salida distinto de cero para falso. ( testes lo mismo que [, excepto por el cierre ])

derobert
fuente
¿Por qué la declaración if no necesita los corchetes? Lo tengo funcionando sin, pero no entiendo por qué. ¿Aún puedo anidarlo sin los soportes?
Lauren
@Lauren, ¿te perdiste la nota rápida? [no es parte de la sintaxis if, es (conceptualmente) un comando que está ejecutando, al igual que grep
derobert
2
@Lauren No usas grep dentro de [, usas uno u otro, dependiendo de la condición que quieras verificar. (Puede usar cualquier comando dentro de un if, por cierto, si solo verifica el código de salida) ... bueno, supongo que probablemente podría encontrar una razón para usar grep dentro de [, pero ese sería un script bastante complicado, y es No es una cosa normal que hacer.
derobert
3
Para su información, ejecute ls -l /usr/bin/\[y man [para ver que [es un programa como cualquier otro, solo parece un elemento sintáctico, esto debería hacerlo obvio y más fácil de entender. (por conveniencia, [también está integrado en bash, dash y otros, pero sigue siendo un comando). También prueba type -all [en bash.
cas
1
@AlexanderCska si desea que grep imprima las líneas coincidentes (por ejemplo, para canalizarlas en algún lugar), luego omita la -qopción, esa opción le dice a grep que esté en silencio (no imprima las líneas coincidentes).
derobert
48

Otra forma simple es usar grep -c.

Eso genera (no devuelve como código de salida), el número de líneas que coinciden con el patrón, por lo que 0 si no hay coincidencia o 1 o más si existe una coincidencia.

Entonces, si desea verificar que el patrón coincida 3 o más veces, debería hacer lo siguiente:

if [ "$(grep -c "^$1" schemas.txt)" -ge 3 ]; then
  ...
amigal
fuente
17
Más precisamente, será la salida 1 si se encuentra sólo una vez. Para generar 1 independientemente de la cantidad de coincidencias encontradas, utilice grep -cim1en su lugar.
manatwork
Este método también se puede utilizar para distinguir entre el error grep y el 'patrón encontrado 0 veces' grep. (aunque no con la declaración if exacta utilizada, creo que se requiere una variable)
Evan Benn
3

Sé que llego tarde a esto, pero me encanta esta versión corta:

grep -q ^$1 schemas.txt && echo "Schema already exists. Please try again" || echo "$@" >> schemas.txt
Denis Pitzalis
fuente
0

Si queremos capturar la primera palabra de un archivo, necesitamos agregar -zwa grep

if grep -qzw "^$1" file
then 
   ... 
else 
   ... 
fi

Sin -znosotros tenemos la primera palabra de una línea. Sin -wnosotros obtenemos palabras parciales.

JJoao
fuente
-2

Si desea usarlo entre corchetes, puede ejecutar lo siguiente

if [ `grep -q PATTERN file.txt` ]; then
    echo found
else
    echo not found

Esta lógica funciona para todos los comandos, solo coloque sus comandos dentro del botón de retroceso (el botón arriba de la pestaña o hacia abajo del botón Esc o hacia la izquierda de 1 botón)

k_vishwanath
fuente
1
Debería citar el `grep -q PATTERN file.txt`, de lo contrario, se aplica el operador split + glob y eso causaría problemas para cualquier salida que contenga caracteres $IFScomodín o caracteres. En términos más generales, [ "`cmd`" ]devolvería verdadero si cmdgenera al menos una línea no vacía en stdout (con problemas potenciales si genera bytes NUL). Eso significa que el shell tendrá que almacenar toda la salida en la memoria y esperar a que termine. Usar en su if cmd | grep -q .lugar puede ser preferible en ese sentido.
Stéphane Chazelas
Este comando no tendría ningún sentido en absoluto. El propósito del -qinterruptor es suprimir grep la salida. Está diciendo: Verifique PATTERN en file.txt, suprima cualquier salida, luego configure el estado de retorno de acuerdo con si se encontró PATTERN. Luego, ignore el estado de retorno, tome la salida del comando (que forzamos a estar vacía), aplique la división de palabras y la expansión global de archivos (sin ningún argumento), luego ejecute el comando [(aka test) con exactamente un argumento, a saber , ]--y luego, dado que eso dará como resultado un error, echo "no encontrado". @ StéphaneChazelas, ¿me perdí algo?
Comodín
1
@Wildcard, tienes razón, aparentemente pasé por alto la -q. Ese comentario habría tenido sentido [ `grep PATTERN file.txt ` ], pero como se insinuó en el comentario, [ "`grep -n PATTERN file.txt`" ]sería mejor si PATTERN pudiera coincidir solo con líneas vacías. Aunque aquí, por supuesto, es lo if grep -q PATTERN file.txtque quieres.
Stéphane Chazelas