supprimer les messages stderr dans un script bash

49

Considérez le nom de script suivant (légèrement idiot) 'test1.sh':

#/bin/bash
#
sleep 10 &
echo sleep pid = $!
pkill sleep

Quand je le lance, je reçois non seulement le résultat de l'écho, mais aussi le compte rendu par bash de la mort du sommeil sur stderr:

$ ./test1.sh
sleep pid = 3551
./test1.sh: line 5:  3551 Terminated              sleep 10

Dans ce cas, j'aimerais supprimer l’impression en stderr. Je sais que je peux le faire en ligne de commande, comme dans:

$ ./test1.sh 2> /dev/null

... mais est - il un moyen de le supprimer de l' intérieur du script? (Je sais que je pourrais l'envelopper dans un second script et le rediriger vers le wrapper, mais il doit y avoir quelque chose de plus facile ...)

intrépide
la source
avez-vous essayé d'ajouter la redirection 2> / dev / null après le sommeil de pkill?
Rahul
@rahul: oui, pkill ne génère pas le message, bash.
fearless_fool
J'ai utilisé kill au lieu de pkill et je ne reçois pas le stderr. étrange ..
Rahul
@rahul: pourrait-il s'agir d'une chose intégrée ou non intégrée? Avez-vous essayé avec pkill aussi?
fearless_fool
oui, je le crois. Je reçois la même erreur avec pkill, mais pas avec kill. Lors de l'utilisation de kill, j'ai utilisé le pid au lieu du nom de proc.
Rahul

Réponses:

73

Vous avez raison; pkill ne génère pas le message, c'est bash. Vous suggérez que

$ ./test1.sh 2> /dev/null

est une solution possible. Comme le souligne UVV, l’action équivalente à partir du script est

exec 2> /dev/null

Cela redirige le stderr du script à /dev/null partir de cette instruction jusqu'à ce qu'il soit modifié. Les moyens maladroits de le reconvertir incluent

exec 2> /dev/tty

qui redirige stderr vers le terminal. C'est probablement (mais pas nécessairement) où il était à l'origine.

Ou

exec 2>&1

ce qui fait que stderr est identique à stdout et risque de se tromper.

Un moyen plus fiable est

exec 3> & 2
exec 2> / dev / null
(faites des choses où vous ne voulez pas voir le stderr.) 
exec 2> & 3

qui enregistre le stderr d’origine dans le descripteur de fichier 3 et le restaure ultérieurement.

Parmi les autres moyens de supprimer l’annonce du décès, citons:

(sleep 10 & pkill sleep) 2> /dev/null

et

{ sleep 10 & pkill sleep;} 2> /dev/null

qui change le stderr uniquement pour les commandes groupées.

Scott
la source
C'est une excellente réponse détaillée. Merci Monsieur!
Keenan Lawrence
Existe-t-il des dangers associés à la sauvegarde stdinet stderraux nouveaux descripteurs de fichier, à l'envoi des descripteurs d'origine /dev/nullpuis à leur restauration?
Alexej Magura
Eh bien, je suppose que si vous exécutiez un programme écrit (à votre insu) dans le descripteur de fichier 3 (ou 4), cette opération échouerait dans des circonstances normales. Mais le programme pourrait être écrit pour ignorer l’échec et continuer sans le signaler; alors vous ne saurez jamais. Mais si votre descripteur de fichier 1 (ou 2) était «parqué» sur le descripteur de fichier 3 (ou 4), alors ce programme serait soudainement en train d'écrire sur la sortie standard de votre script ou sur stderr. Mais c'est un exemple très artificiel, et toujours un danger minime. Aviez-vous quelque chose en tête?
Scott
1
FWIW, je suis favorable à l’approche du commandement groupé de Scott, c’est{ sleep 10 & pkill sleep;} 2> /dev/null
fearless_fool
9

Selon cela, vous pourriez faire quelque chose comme suit:

#!/bin/bash
exec 2>/dev/null
ls -al test
UVV
la source