Comment faire «sinon une vraie condition»?

317

J'aimerais que la echocommande soit exécutée quand ce cat /etc/passwd | grep "sysa"n'est pas vrai.

Qu'est-ce que je fais mal?

if ! [ $(cat /etc/passwd | grep "sysa") ]; then
        echo "ERROR - The user sysa could not be looked up"
        exit 2
fi
Sandra Schlichting
la source
7
Ne devrait-il !pas être à l'intérieur des supports? ie[ ! EXPR ]
acraig5075
7
@ acraig5075 c'est valide dans les deux cas, mais il n'y a aucun besoin d'une commande de test (ce que sont les crochets) dans cette instruction.
Charles Duffy

Réponses:

455

essayer

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

greprenvoie trues'il trouve la cible de recherche et falses'il ne le fait pas.

Donc PAS false== true.

if Les évaluations dans les shells sont conçues pour être très flexibles, et souvent ne nécessitent pas de chaînes de commandes (comme vous l'avez écrit).

De plus, en regardant votre code tel $( ... )quel , votre utilisation de la forme de substitution cmd est à recommander, mais pensez à ce qui sort du processus. Essayez echo $(cat /etc/passwd | grep "sysa")de voir ce que je veux dire. Vous pouvez aller plus loin en utilisant l' -coption (count) pour grep et ensuite faire if ! [ $(grep -c "sysa" /etc/passwd) -eq 0 ] ; thence qui fonctionne mais est plutôt old school.

MAIS, vous pouvez utiliser les dernières fonctionnalités du shell (évaluation arithmétique) comme

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

ce qui vous donne également l'avantage d'utiliser les opérateurs de comparaison basés sur c-lang, ==,<,>,>=,<=,%et peut-être quelques autres.

Dans ce cas, selon un commentaire d'Orwellophile, l'évaluation arithmétique peut être encore plus détaillée, comme

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

OU

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

Enfin, il existe un prix appelé Useless Use of Cat (UUOC). :-) Certaines personnes vont sauter de haut en bas et pleurer gothca! Je dirai simplement que greppeut prendre un nom de fichier sur sa ligne de commande, alors pourquoi invoquer des processus et des constructions de tuyaux supplémentaires lorsque vous n'êtes pas obligé? ;-)

J'espère que ça aide.

shellter
la source
1
Tout cela est plutôt stupide, de ma réponse à une question beaucoup plus difficile ( stackoverflow.com/a/30400327/912236] grep "^$user:" /etc/passwd serait la façon la plus correcte de rechercher / etc / passwd accessoirement - grep -v-v inverse la recherche si vous le souhaitez pour éviter le désordre de ||
Orwellophile
1
oui, eh bien, il y a une solution plus efficace à un problème, puis il y a une réponse à une question précise. J'ai essayé de répondre à la question spécifique. Merci pour vos idées. Bonne chance à tous.
shellter
1
ne pas cueillir vos réponses, les a bien appréciées. Je viens de lancer un chèque correctement délimité sur le nom d'utilisateur, sinon si l'OP recherche vraiment sur "sys" ou quelque chose, il aura la surprise. un de plus pour la route? (( $( cat file | grep regex | wc -l ) ? 0 : 1 ))
Orwellophile
1
Génial! Pour une raison quelconque, reqular "! Grep -qs ..." ne fonctionnait pas avec / proc / mounts et essayait de savoir si un disque USB tombant régulièrement était monté sur le noyau Raspbian 4.9. Celui-ci a parfaitement fait le travail!
DocWeird
33

Je pense que cela peut être simplifié en:

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

ou dans une seule ligne de commande

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

Rony
la source
4
Bien, mais je préfère la réponse de M. shellter parce qu'elle est "auto-documentée", est plus "lisible" l'intention du programmeur.
0zkr PM le
1
J'aime cette version. Que diriez-vous d'ajouter 1>&2à la fin de votre echoimpression stderr?
Julien
2
@ 0zkrPM Mais la version shellter ne fonctionne pas en Bourne shell. Vous obtiendrez!: not found
ceving
1
Évitez la redirection de sortie lorsque vous utilisez 'grepcomme ceci. -qsupprime la sortie.
tbc0
8

Qu'est-ce que je fais mal?

$(...)détient la valeur , pas le statut de sortie, c'est pourquoi cette approche est erronée. Cependant, dans ce cas spécifique, cela fonctionne bien car sysail sera imprimé, ce qui rendra la déclaration de test vraie. Cependant, if ! [ $(true) ]; then echo false; fiserait toujours imprimé falsecar la truecommande n'écrit rien sur stdout (même si le code de sortie est 0). C'est pourquoi il doit être reformulé if ! grep ...; then.

Une alternative serait cat /etc/passwd | grep "sysa" || echo error. Edit: Comme Alex a fait remarquer, le chat est inutile ici : grep "sysa" /etc/passwd || echo error.

J'ai trouvé les autres réponses assez confuses, j'espère que cela aide quelqu'un.

phil294
la source
1

Sur les systèmes Unix qui le supportent (pas macOS semble-t-il):

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

Cela présente l'avantage d'interroger tout service d'annuaire éventuellement utilisé (YP / NIS ou LDAP, etc.) et le fichier de base de données de mots de passe local.


Le problème avec grep -q "$username" /etc/passwdest qu'il donnera un faux positif quand il n'y a pas un tel utilisateur, mais quelque chose d'autre correspond au modèle. Cela peut se produire s'il existe une correspondance partielle ou exacte ailleurs dans le fichier.

Par exemple, dans mon passwddossier, il y a une ligne disant

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

Cela provoquerait une correspondance valide sur des choses comme caraet enocetc., même s'il n'y a pas de tels utilisateurs sur mon système.

Pour qu'une grepsolution soit correcte, vous devrez analyser correctement le /etc/passwdfichier:

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

... ou tout autre test similaire par rapport au premier des :champs délimités.

Kusalananda
la source
@SDsolar Votre code n'est probablement pas exécuté par bashdans ce cas.
Kusalananda
1

Voici une réponse à titre d'exemple:

Afin de s'assurer que les enregistreurs de données sont en ligne, un cronscript s'exécute toutes les 15 minutes et ressemble à ceci:

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

... et ainsi de suite pour chaque enregistreur de données que vous pouvez voir dans le montage à http://www.SDsolarBlog.com/montage


Pour info, en utilisant &>/dev/nullredirige toutes les sorties de la commande, y compris les erreurs, vers/dev/null

(Le conditionnel ne nécessite que exit statusla pingcommande)

Pour info aussi, notez que depuis cron travaux s'exécutent car rootil n'est pas nécessaire de les utiliser sudo pingdans un cronscript.

SDsolar
la source