Come rendere "se non vera condizione"?


317

Vorrei che il echocomando fosse eseguito quando cat /etc/passwd | grep "sysa"non è vero.

Che cosa sto facendo di sbagliato?

if ! [ $(cat /etc/passwd | grep "sysa") ]; then
        echo "ERROR - The user sysa could not be looked up"
        exit 2
fi

7
Il !non dovrebbe essere all'interno delle parentesi? vale a dire[ ! EXPR ]
acraig5075,

7
@ acraig5075 è valido in entrambi i casi, ma non è necessario un comando di test (che è quello che è tra parentesi) in questa istruzione.
Charles Duffy,

Risposte:


455

provare

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

grepritorna truese trova il target di ricerca e falsese non lo fa.

Quindi NON false== true.

if la valutazione nelle shell è progettata per essere molto flessibile e molte volte non richiede catene di comandi (come hai scritto).

Inoltre, guardando il tuo codice così com'è, il tuo uso della $( ... )forma di sostituzione cmd deve essere lodato, ma pensa a cosa sta uscendo dal processo. Prova echo $(cat /etc/passwd | grep "sysa")a capire cosa intendo. Puoi andare oltre usando l' -copzione (count) per grep e poi fare if ! [ $(grep -c "sysa" /etc/passwd) -eq 0 ] ; thenquale funziona ma è piuttosto vecchia scuola.

MA, potresti usare le più recenti funzionalità di shell (valutazione aritmetica) come

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

che offre anche il vantaggio di utilizzare gli operatori di confronto basati su c-lang ==,<,>,>=,<=,%e forse alcuni altri.

In questo caso, per un commento di Orwellophile, la valutazione aritmetica può essere ulteriormente ridotta, come

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

O

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

Infine, c'è un premio chiamato il Useless Use of Cat (UUOC). :-) Alcune persone salteranno su e giù e piangeranno gothca! Dirò solo che greppuò prendere un nome di file sulla sua linea cmd, quindi perché invocare processi extra e costruzioni di pipe quando non è necessario? ;-)

Spero che aiuti.


1
È davvero piuttosto sciocco, dalla mia risposta a una domanda (molto più difficile) [ stackoverflow.com/a/30400327/912236] grep "^$user:" /etc/passwd sarebbe il modo più corretto di cercare / etc / passwd per caso - grep -vdove -v inverte la ricerca se lo desideri per evitare il caos di ||
Orwellophile,

1
sì, beh, c'è un problema che risolve il problema in modo più efficiente e quindi c'è una risposta a una domanda specifica. Ho provato a rispondere alla domanda specifica. Grazie per le tue idee Buona fortuna a tutti.
shellter

1
non raccogliendo le tue risposte, mi sono divertito molto. solo attraverso vorrei lanciare un controllo delimitato correttamente sul nome utente, altrimenti se l'OP cerca davvero "sys" o qualcosa del genere, otterrà piuttosto la sorpresa. Uno in più per la strada? (( $( cat file | grep regex | wc -l ) ? 0 : 1 ))
Orwellophile,

1
Grande! Per qualche motivo, reqular "! Grep -qs ..." non ha funzionato con / proc / mounts e ha cercato di scoprire se un disco USB a rilascio regolare era montato sul kernel Raspbian 4.9. Questo ha fatto perfettamente il lavoro!
DocWeird,

33

Penso che possa essere semplificato in:

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

o in una singola riga di comando

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


4
Bello, ma preferisco la risposta di Mr. shellter perché è "auto-documentato", è più "leggibile" l'intenzione del programmatore.
0zkr PM,

1
Mi piace questa versione. Che ne dici di aggiungere 1>&2alla fine del tuo echoper stampare stderr?
Julien,

2
@ 0zkrPM Ma la versione shellter non funziona nella shell Bourne. Si otterrà!: not found
ceving

1
Evitare il reindirizzamento dell'output quando si utilizza in 'grepquesto modo. -qsopprime l'output.
martedì

8

Che cosa sto facendo di sbagliato?

$(...)contiene il valore , non lo stato di uscita, ecco perché questo approccio è sbagliato. Tuttavia, in questo caso specifico, funziona davvero perché sysaverrà stampato il che rende la dichiarazione di prova realtà. Tuttavia, if ! [ $(true) ]; then echo false; fistampa sempre falseperché il truecomando non scrive nulla su stdout (anche se il codice di uscita è 0). Ecco perché deve essere riformulato if ! grep ...; then.

Un'alternativa sarebbe cat /etc/passwd | grep "sysa" || echo error. Edit: Come Alex ha sottolineato, il gatto è inutile qui : grep "sysa" /etc/passwd || echo error.

Ho trovato le altre risposte piuttosto confuse, spero che questo aiuti qualcuno.


1

Sui sistemi Unix che lo supportano (non macOS sembra):

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

Ciò ha il vantaggio di interrogare qualsiasi servizio di directory che potrebbe essere in uso (YP / NIS o LDAP ecc.) E il file di database delle password locali.


Il problema grep -q "$username" /etc/passwdè che darà un falso positivo quando non esiste tale utente, ma qualcos'altro corrisponde allo schema. Ciò può accadere se esiste una corrispondenza parziale o esatta da qualche altra parte nel file.

Ad esempio, nel mio passwdfile, c'è una riga che dice

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

Ciò provocherebbe una corrispondenza valida su cose come carae così enocvia, anche se non ci sono tali utenti sul mio sistema.

Affinché una grepsoluzione sia corretta, sarà necessario analizzare correttamente il /etc/passwdfile:

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

... o qualsiasi altro test simile contro il primo dei :campi delimitati.


@SDsolar bashIn questo caso probabilmente il tuo codice non viene eseguito .
Kusalananda,

1

Ecco una risposta a titolo di esempio:

Per assicurarsi che i data logger siano online, cronogni 15 minuti viene eseguito uno script simile al seguente:

#!/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
#

... e così via per ogni registratore di dati che è possibile visualizzare nel montaggio all'indirizzo http://www.SDsolarBlog.com/montage


Cordiali saluti, utilizzando &>/dev/nullreindirizza tutto l'output dal comando, inclusi gli errori, a/dev/null

(Il condizionale richiede solo exit statusil pingcomando)

Inoltre, notare che poiché i cronlavori vengono eseguiti in quanto rootnon è necessario utilizzarli sudo pingin uno cronscript.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.