¿Cómo hacer "si no es verdadera condición"?

317

Me gustaría echoejecutar el comando cuando cat /etc/passwd | grep "sysa"no sea cierto.

¿Qué estoy haciendo mal?

if ! [ $(cat /etc/passwd | grep "sysa") ]; then
        echo "ERROR - The user sysa could not be looked up"
        exit 2
fi
Sandra Schlichting
fuente
77
¿ !No debería estar dentro de los corchetes? es decir[ ! EXPR ]
acraig5075
77
@ acraig5075 es válido de cualquier manera, pero no hay necesidad de un comando de prueba (que es lo que son los corchetes) en esta declaración.
Charles Duffy

Respuestas:

455

tratar

if ! grep -q sysa /etc/passwd ; then

grepregresa truesi encuentra el objetivo de búsqueda y falsesi no lo hace.

Entonces NO false== true.

if La evaluación en shells está diseñada para ser muy flexible, y muchas veces no requiere cadenas de comandos (como ha escrito).

Además, al mirar su código tal como está, $( ... )se debe recomendar el uso de la forma de sustitución de cmd, pero piense en lo que está saliendo del proceso. Intenta echo $(cat /etc/passwd | grep "sysa")ver a qué me refiero. Puede llevarlo más allá utilizando la -copción (contar) para grep y luego hacer lo if ! [ $(grep -c "sysa" /etc/passwd) -eq 0 ] ; thenque funciona, pero es bastante antiguo.

PERO, podría usar las funciones de shell más recientes (evaluación aritmética) como

if ! (( $(grep -c "sysa" /etc/passwd) == 0 )) ; then ...`

lo que también le brinda el beneficio de usar los operadores de comparación basados ​​en c-lang, ==,<,>,>=,<=,%y tal vez algunos otros.

En este caso, según un comentario de Orwellophile, la evaluación aritmética se puede reducir aún más, como

if ! (( $(grep -c "sysa" /etc/passwd) )) ; then ....

O

if (( ! $(grep -c "sysa" /etc/passwd) )) ; then ....

Finalmente, hay un premio llamado Useless Use of Cat (UUOC). :-) ¡Algunas personas saltan arriba y abajo y lloran gothca! Solo diré que greppuede tomar un nombre de archivo en su línea cmd, entonces, ¿por qué invocar procesos adicionales y construcciones de tuberías cuando no es necesario? ;-)

Espero que esto ayude.

cáscara
fuente
1
Todo es bastante tonto realmente, desde mi respuesta a una pregunta mucho más difícil [ stackoverflow.com/a/30400327/912236] grep "^$user:" /etc/passwd sería la forma más correcta de buscar / etc / passwd incidentalmente, grep -vdonde -v invierte la búsqueda si lo desea para evitar el desorden de ||
Orwellophile
1
Sí, bueno, hay que resolver un problema de la manera más eficiente, y luego hay una pregunta específica. Intenté responder la pregunta específica. Gracias por tus ideas. Buena suerte a todos.
shellter 01 de
1
sin elegir sus respuestas, las disfruté bastante. solo por terminar, arrojaría un cheque debidamente acotado en el nombre de usuario, de lo contrario, si el OP realmente busca en "sys" o algo así, obtendrá una gran sorpresa. uno más para el camino? (( $( cat file | grep regex | wc -l ) ? 0 : 1 ))
Orwellophile
1
¡Excelente! Por alguna razón, reqular "! Grep -qs ..." no funcionaba con / proc / mounts e intentaba averiguar si se montaba un disco USB que caía regularmente en el kernel Raspbian 4.9. ¡Este hizo el trabajo perfectamente!
DocWeird
33

Creo que se puede simplificar en:

grep sysa /etc/passwd || {
    echo "ERROR - The user sysa could not be looked up"
    exit 2
}

o en una sola línea de comando

$ grep sysa /etc/passwd || { echo "ERROR - The user sysa could not be looked up"; exit 2; }

Rony
fuente
44
Agradable, pero prefiero la respuesta de Mr. Shellter porque es "auto documentada", es más "legible" la intención del programador.
0zkr PM
1
Me gusta esta version ¿Qué hay de agregar 1>&2al final de su echopara imprimir stderr?
Julien
2
@ 0zkrPM Pero la versión de shell no funciona en el shell Bourne. Obtendrá!: not found
ceving
1
Evite la redirección de salida cuando se usa de 'grepesta manera. -qsuprime la salida.
tbc0
8

¿Qué estoy haciendo mal?

$(...)contiene el valor , no el estado de salida, es por eso que este enfoque es incorrecto. Sin embargo, en este caso específico, sí funciona porque sysase imprimirá, lo que hace que la declaración de prueba se haga realidad. Sin embargo, if ! [ $(true) ]; then echo false; fisiempre se imprimiría falseporque el truecomando no escribe nada en stdout (aunque el código de salida sea 0). Por eso es necesario reformularlo if ! grep ...; then.

Una alternativa sería cat /etc/passwd | grep "sysa" || echo error. Edit: Como Alex señaló, el gato es inútil aquí : grep "sysa" /etc/passwd || echo error.

Encontraron las otras respuestas bastante confusas, espero que esto ayude a alguien.

phil294
fuente
1

En sistemas Unix que lo soportan (no macOS parece):

if getent passwd "$username" >/dev/null; then
    printf 'User %s exists\n' "$username"
else
    printf 'User %s does not exist\n' "$username"
fi 

Esto tiene la ventaja de que consultará cualquier servicio de directorio que pueda estar en uso (YP / NIS o LDAP, etc.) y el archivo de base de datos de contraseñas local.


El problema con grep -q "$username" /etc/passwdes que dará un falso positivo cuando no exista ese usuario, pero algo más coincide con el patrón. Esto podría suceder si hay una coincidencia parcial o exacta en otro lugar del archivo.

Por ejemplo, en mi passwdarchivo, hay una línea que dice

build:*:21:21:base and xenocara build:/var/empty:/bin/ksh

Esto provocaría una coincidencia válida en cosas como caray enocetc., a pesar de que no hay usuarios en mi sistema.

Para que una grepsolución sea correcta, deberá analizar el /etc/passwdarchivo correctamente :

if cut -d ':' -f 1 /etc/passwd | grep -qxF "$username"; then
    # found
else
    # not found
fi

... o cualquier otra prueba similar contra el primero de los :campos delimitados.

Kusalananda
fuente
@SDsolar Su código probablemente no se ejecute bashen ese caso.
Kusalananda
1

Aquí hay una respuesta a modo de ejemplo:

Para asegurarse de que los registradores de datos estén en línea, se cronejecuta un script cada 15 minutos que se ve así:

#!/bin/bash
#
if ! ping -c 1 SOLAR &>/dev/null
then
  echo "SUBJECT:  SOLAR is not responding to ping" | ssmtp abc@def.com
  echo "SOLAR is not responding to ping" | ssmtp 4151112222@txt.att.com
else
  echo "SOLAR is up"
fi
#
if ! ping -c 1 OUTSIDE &>/dev/null
then
  echo "SUBJECT:  OUTSIDE is not responding to ping" | ssmtp abc@def.com
  echo "OUTSIDE is not responding to ping" | ssmtp 4151112222@txt.att.com
else
  echo "OUTSIDE is up"
fi
#

... y así sucesivamente para cada registrador de datos que puede ver en el montaje en http://www.SDsolarBlog.com/montage


Para su información, el uso &>/dev/nullredirige todos los resultados del comando, incluidos los errores, a/dev/null

(El condicional solo requiere exit statusel pingcomando)

También para su información, tenga en cuenta que dado que los crontrabajos se ejecutan ya que rootno hay necesidad de usarlos sudo pingen un cronscript.

SDsolar
fuente