Comment canaliser la sortie d'un process à un autre mais seulement l'exécuter si le premier a une sortie?

Comment puis-je réécrire cette command uniquement pour envoyer un e-mail s'il y a une sortie du mailq | grep mailq | grep ?

 mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -s 'dd' email@email 

Est-ce même possible sur une seule ligne?

Voir Vérifier si le canal est vide et exécuter une command sur datatables si ce n'est pas pour un cas plus général que d'envoyer des emails.

Je pense que vous devrez utiliser un file temporaire pour cette opération afin que vous puissiez utiliser l'opérateur && pour exécuter la command mail uniquement si le grep a renvoyé un état de sortie indiquant qu'il avait des correspondances comme ceci:

 TMPFILE=`mktemp /tmp/mailqgrep.XXXXXX`; mailq | egrep 'rejected|refused' -A5 -B5 > "$TMPFILE" && mail -s 'dd' email@email < "$TMPFILE"; rm "$TMPFILE" 

Si cela ne vous dérangeait pas que le file temporaire soit collé quelque part et que vous puissiez utiliser un nom statique pour cela, vous pouvez ignorer les options spéciales de nommage et de suppression:

  mailq | egrep 'rejected|refused' -A5 -B5 > /tmp/mailqgrep && mail -s 'dd' email@email < /tmp/mailqgrep 

Edit: Après avoir vu la réponse de Glenn, j'ai joué un peu plus et apparemment assigner une variable en utilisant la syntaxe $() renvoie le code de sortie de la command, donc vous pouvez ignorer le test qu'il a utilisé pour la longueur de string et l'utiliser à la place. Ici tout est dans une seule command:

 data=$(mailq | egrep 'rejected|refused' -A 5 -B 5) && mail -s 'dd' email@email <<< "$data" 

Edit 2: Après avoir vu la réponse de Simon, j'ai vérifié mon programme de mail . Il ne se comporte pas comme il le décrit par défaut, mais il a une option pour cela. De la page de manuel:

-E Si un message sortant ne contient aucun text dans sa première ou seule partie de message, ne l'envoyez pas mais supprimez-le en silence, en définissant efficacement la variable skipemptybody au démarrage du programme. Ceci est utile pour envoyer des messages à partir de scripts lancés par cron (8).

Rendre cela possible:

 mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -E -s 'dd' email@email 

Vous pouvez save la sortie dans une variable, puis appeler la command mail si la longueur de la string est différente de zéro.

 data=$(mailq | egrep 'rejected|refused' -A 5 -B 5) [[ -n "$data" ]] && mail -s 'dd' email@email <<< "$data" 

Pour une ligne, joignez les deux commands avec un point-virgule.

Le programme utilitaire ifne existe expressément à cette fin: pour exécuter une command si l'input standard n'est pas vide.

 mailq | egrep 'rejected|refused' -A 5 -B 5 | ifne mail -s 'dd' email@email 

La command ifne fait partie du packageage de moreutils , présenté comme «une collection croissante d'outils Unix que personne n'a pensé à écrire il y a longtime, alors qu'Unix était jeune».

Utilisez le mail avec l'option -E . Sur mon Mac, MAIL (1) dit que le drapeau -E n'enverra pas d'e-mail avec un corps vide.

-E Ne pas envoyer de messages avec un corps vide. Ceci est utile pour les erreurs de piping des scripts cron (8).

Sur mon Mac, j'ai exécuté le test suivant. Notez que le file file_does_exist existe, mais le file file_does__not_exist n'existe pas.

Ceci envoie un email à moi:

 $ ls file_does_exist | egrep 'file' -A5 -B5 | mailx -E -s 'test' [email protected] 

Ce n'est pas le cas. Notez que la command ls file_does_not_exist | egrep ... ls file_does_not_exist | egrep ... ne produit aucune sortie.

 $ ls file_does_not_exist | egrep 'file' -A5 -B5 | mailx -E -s 'test' [email protected] ls: file_does_not_exist: No such file or directory 

Dans ce cas particulier, si votre mail prend en charge l'option -E , utilisez-le. Dans le cas général, vous pouvez essayer de lire un caractère; s'il y en a un, lancez la command de post-traitement et ajoutez-la à ce caractère du rest du file.

 pipe_if_not_empty () { a=$(dd bs=1 count=1 2>/dev/null; echo .) # read at most one character if [ "$a" != "." ]; then # if there were two characters, { printf %s "${a%.}"; # then output the first character cat; } | # and the rest of the input "$@" # into the specified program fi } mailq | egrep 'rejected|refused' -A 5 -B 5 | pipe_if_not_empty mail -s 'dd' email@email 

Notez l'utilisation utile de cat . L'ajout de l' echo . rend cette fonction fonctionnelle même si le premier caractère de l'input est une nouvelle ligne (callbackez-vous que la construction $(…) dénature les lignes de return).

Avec la plupart des shells (rien d'autre que zsh, pour autant que je sache), si le file commence par un caractère nul, ce code croira qu'il est vide. Fixation qui est laissé comme un exercice pour le lecteur. (Astuce: utilisez od dans le premier sous-shell et printf pour imprimer le premier octet.) (Solution: Comment vérifier si le tube est vide ) Vous pourriez rencontrer le même problème si le file commence par un octet qui n'est pas valide l'environnement local actuel; c'est plus facile à résoudre en exécutant ce code avec LC_ALL=C

IIRC la command mail BSD s'interrompt si un message vide est fourni.

Vous pouvez réécrire votre command à l'aide de test -s /dev/stdin pour vérifier s'il existe une sortie du mailq | grep partie mailq | grep .

 - mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -s 'dd' email@email + mailq | egrep 'rejected|refused' -A 5 -B 5 | (test -s /dev/stdin && cat) | mail -s 'dd' email@email 

Récemment, j'ai appris le nom de la command ifne qui fait partie du packageage moreutils . Où vous pouvez l'utiliser pour résoudre ce problème spécifique.

ifne – Exécute la command si l'input standard n'est pas vide

exemple de la page de manuel,

 EXAMPLE find . -name core | ifne mail -s "Core files found" root