web-dev-qa-db-fra.com

Empêcher grep de renvoyer une erreur lorsque l'entrée ne correspond pas

Je veux écrire dans un script bash un morceau de code qui vérifie si un programme est déjà en cours d'exécution. J'ai les informations suivantes pour rechercher si la barre est en cours d'exécution

 foo=`ps -ef | grep bar | grep -v grep`

Le

 grep -v grep

une partie est de s'assurer que la "barre grep" n'est pas prise en compte dans les résultats ps

Lorsque la barre ne fonctionne pas, foo est correctement vide. Mais mon problème réside dans le fait que le script a

 set -e

qui est un indicateur pour terminer le script si une commande renvoie une erreur. Il s'avère que lorsque la barre n'est pas en cours d'exécution, "grep -v grep" ne correspond à rien et grep renvoie une erreur. J'ai essayé d'utiliser -q ou -s mais en vain.

Y a-t-il une solution à cela? THX

61
George Kastrinis

Sûr:

ps -ef | grep bar | { grep -v grep || true; }

Ou même:

ps -ef | grep bar | grep -v grep | cat
62
Sean

Une bonne astuce pour éviter grep -v grep est-ce:

ps -ef | grep '[b]ar'

Cette expression régulière ne correspond qu'à la chaîne "bar". Cependant, dans la sortie ps, la chaîne "bar" n'apparaît pas avec le processus grep.


Dans les jours qui m'ont précédé sur pgrep, j'ai écrit cette fonction pour automatiser la commande ci-dessus:

psg () { 
    local -a patterns=()
    (( $# == 0 )) && set -- $USER
    for arg do
        patterns+=("-e" "[${arg:0:1}]${arg:1}")
    done
    ps -ef | grep "${patterns[@]}"
}

Alors,

psg foo bar

se transforme en

ps -ef | grep -e '[f]oo' -e '[b]ar'
15
glenn jackman

Pourquoi demander à ps de fournir des quantités massives de sortie avec -ef si vous n'en jetez que 99%? ps et surtout la version GNU est un couteau suisse de fonctionnalité pratique. Essayez ceci:

ps -C bar -o pid= 1>/dev/null

Je précise -o pid= ici juste parce que, mais en fait c'est inutile puisque nous jetons toute la sortie de toute façon. Il serait cependant utile de connaître le PID en cours d'exécution.

ps retournera automatiquement avec un état d'existence différent de zéro si -C ne correspond à rien et avec zéro s'il correspond. Vous pouvez donc simplement dire ceci

ps -C bar 1>/dev/null && echo bar running || echo bar not running

Ou

if ps -C bar 1>/dev/null ; then
    echo bar running
else
    echo bar not running
fi

N'est-ce pas plus simple? Pas besoin de grep, pas deux ou même une fois.

10
Sorpigal

Réponse courte

Écrire

ps -ef | grep bar | { grep -v grep || test $? = 1; }

si vous utilisez set -e.

Si vous utilisez l'option bash pipefail (set -o pipefail), N'oubliez pas d'appliquer la gestion des exceptions (||test) à chaque grep du pipeline:

ps -ef | { grep bar || test $? = 1; } | { grep -v grep || test $? = 1; }

Dans Scripts Shell je vous suggère d'utiliser la fonction utilitaire ”catch-1-grep“ (c1grep):

c1grep() { grep "$@" || test $? = 1; }

Expliqué

grep Le statut de sortie de _ est 0, 1 ou 2: [1]

  • 0 Signifie qu'une ligne est sélectionnée
  • 1 Signifie qu'aucune ligne n'a été sélectionnée
  • 2 Signifie qu'une erreur s'est produite

grep peut également renvoyer d'autres codes s'il est interrompu par un signal (par exemple 130 pour SIGINT).

Puisque nous voulons uniquement ignorer le statut de sortie 1, Nous utilisons test pour supprimer ce statut de sortie spécifique.

  • Si grep renvoie 0, test n'est pas exécuté.
  • Si grep renvoie 1, test est exécuté et renvoie 0.
  • Si grep renvoie toute autre valeur, test est exécutée et renvoie 1.

Dans le dernier cas, le script se fermera immédiatement en raison de set -e Ou set -o pipefail. Cependant, si vous ne vous souciez pas du tout des erreurs grep, vous pouvez bien sûr écrire

ps -ef | grep bar | { grep -v grep || true; }

comme suggéré par Sean .


utilisation [supplémentaire] dans les scripts Shell

Dans les scripts Shell, si vous utilisez beaucoup grep, je vous suggère de définir une fonction utilitaire:

# "catch exit status 1" grep wrapper
c1grep() { grep "$@" || test $? = 1; }

De cette façon, votre pipe redeviendra courte et simple, sans perdre les fonctionnalités de set -e Et set -o pipefail:

ps -ef | c1grep bar | c1grep -v grep

Pour info:

  • Je l'ai appelé c1grep Pour souligner qu'il attrape simplement le statut de sortie 1, Rien d'autre.
  • J'aurais pu appeler la fonction grep à la place (grep() { env grep "$@" ...; }), mais je préfère un nom moins confus et plus explicite, c1grep.

[1] grep page de manuel

9
myrdd
foo=`ps -ef | grep bar | grep -v grep` || true
1
DigitalRoss

Essayez de le faire:

ps auxw | grep -v grep | chat

cat renvoie toujours 0 et ignore le code de sortie de grep

1