écho qui sort vers stderr

1116

Existe-t-il un outil Bash standard qui agit comme un écho mais sort vers stderr plutôt que stdout?

Je sais que je peux le faire, echo foo 1>&2mais c'est un peu moche et, je suppose, sujet aux erreurs (par exemple, plus susceptibles de se tromper lorsque les choses changent).

BCS
la source

Réponses:

1454

Vous pouvez le faire, ce qui facilite la lecture:

>&2 echo "error"

>&2copie le descripteur de fichier # 2 dans le descripteur de fichier # 1. Par conséquent, après cette redirection est effectuée, les deux descripteurs de fichiers se référeront au même fichier: le descripteur d' un fichier # 2 a été à l' origine référence. Pour plus d'informations, consultez le didacticiel de redirection illustré de Bash Hackers .

Marco Aurelio
la source
2
J'ai appris cette astuce il y a un bon moment. Cette page contient de bonnes informations. tldp.org/LDP/abs/html/io-redirection.html
Marco Aurelio
46
@BCS Je ne sais pas comment utiliser un aliasscript shell. Il serait probablement plus sûr à utilisererrcho(){ >&2 echo $@; }
Braden Best
3
> & 2 est normalement mis à la fin. Cela fonctionnera, mais son utilisation est moins fréquente
Iskren Ivov Chernev
159
Depuis près de 40 ans que j'utilise des systèmes de type Unix, il ne m'est jamais venu à l'esprit que vous pouviez mettre la redirection n'importe où mais à la fin. Le mettre en avant comme ça le rend beaucoup plus évident (ou "facilite la lecture" comme le dit @MarcoAurelio). +1 pour m'avoir appris quelque chose de nouveau.
Hephaestus
FYI: si vous voulez formater ou faire autre chose que simplement faire écho à la chaîne, vous devrez déplacer la redirection vers la fin. Par exemple errcho(){ >&2 echo $@|pr -To5;}, ne fonctionnera pas. Pour faire quelque chose comme ça, vous devrez mettre la redirection quelque part après la dernière pipe comme:errcho(){ echo $@|>&2 pr -To5;}
Jon Red
424

Vous pouvez définir une fonction:

echoerr() { echo "$@" 1>&2; }
echoerr hello world

Ce serait plus rapide qu'un script et sans dépendances.

La suggestion spécifique à bash de Camilo Martin utilise une "chaîne ici" et affichera tout ce que vous lui passerez, y compris les arguments (-n) que l'écho avalerait normalement:

echoerr() { cat <<< "$@" 1>&2; }

La solution de Glenn Jackman évite également le problème de déglutition des arguments:

echoerr() { printf "%s\n" "$*" >&2; }
James Roth
la source
7
Je dois dire que l'écho n'est pas fiable. echoerr -ne xtne va pas imprimer "-ne xt". Mieux vaut l'utiliser printfpour ça.
Camilo Martin
10
Oh, vous pouvez aussi utiliser le chat:echoerr() { cat <<< "$@" 1>&2; }
Camilo Martin
2
Je n'étais pas au courant de ça. Ajoutée.
James Roth
4
Ou,printf "%s\n" "$*" >&2
glenn jackman
4
@GKFX Bien sûr, cela ne fonctionne correctement que lorsque vous citez. Pourquoi les gens ne citent pas leurs chaînes me dépasse. (lorsque vous ne citez pas, tout ce qui est séparé par un ou plusieurs $IFSespaces blancs est envoyé comme un argument séparé, ce qui dans le cas des echomoyens les concatène avec 0x20s, mais les dangers de ne pas citer beaucoup surestiment la commodité de 2 caractères de moins à taper) .
Camilo Martin
252

Puisque 1c'est la sortie standard, vous n'avez pas besoin de la nommer explicitement devant une redirection de sortie comme >mais à la place vous pouvez simplement taper:

echo Ce message va à stderr> & 2

Étant donné que vous semblez inquiet de ce que vous 1>&2aurez du mal à taper de manière fiable, l'élimination du redondant 1pourrait être un léger encouragement pour vous!

Brandon Rhodes
la source
59

Une autre option

echo foo >>/dev/stderr
Steven Penny
la source
4
Cette option est-elle portable? Est-ce que quelqu'un sait si cela ne fonctionne pas pour une certaine saveur unix?
Dacav
7
Cela ne fonctionne pas dans certains chroots, qui ne peuvent pas accéder à / dev / stderr.
Zachary Vance
12
Si le script qui exécute cette ligne - appelons-le foo- a son propre stderr redirigé - par exemple foo >foo.log 2>&1- alors echo foo >/dev/stderrencombrera toutes les sorties avant lui. >>devrait être utilisé à la place:echo foo >>/dev/stderr
doshea
De même, vous avez /dev/fd/2.
jbruni
@Dacav ceci est pour portable que: /proc/self/fd/2. Voir ma réponse ci-dessous :)
Sebastian
32

Non, c'est la façon standard de procéder. Cela ne devrait pas provoquer d'erreurs.

Matthew Flaschen
la source
9
Cela ne devrait pas provoquer d'erreurs, mais je serais plus susceptible de le faire. OTOH ce n'est pas si grave.
BCS
6
@Mike DeSimone: Si quelqu'un d'autre joue avec le code, mélange la sortie et ne sait pas vraiment bash, il pourrait facilement supprimer (ou mal saisir) le fichier 1>&2. Nous souhaitons tous que cela ne se produise pas, mais je suis sûr que nous avons tous été des endroits où cela se produit.
Cascabel
2
( echo something 1>&2 ; something else ) > log-> (echo something; cp some junk 1>&2 ; something else) > logOups.
BCS
30
À mon humble avis, si quelqu'un joue avec le code et ne sait pas bash, cela peut être le moindre de vos problèmes.
Mike DeSimone
8
Je pense que si cela risque d'être un problème, vous devriez commencer à utiliser un langage différent: essayer de rendre bash à toute épreuve est une aventure de dupe.
intuition
17

Si cela ne vous dérange pas de consigner également le message dans syslog, la méthode not_so_ugly est la suivante:

logger -s $msg

L'option -s signifie: "Envoyer le message à l'erreur standard ainsi qu'au journal système."

Grzegorz Luczywo
la source
1
c'est bien! est-il portable?
code_monk
@code_monk: La commande de l' enregistreur devrait être la norme IEEE 1003.2 ( « POSIX.2 ») compatible, la commande de l' enregistreur fait partie du paquet util-linux et est disponible à partir du noyau Linux Archives de kernel.org/pub/linux/utils / util- linux⟩.
miku
12

Il s'agit d'une simple fonction STDERR, qui redirige l'entrée de canal vers STDERR.

#!/bin/bash
# *************************************************************
# This function redirect the pipe input to STDERR.
#
# @param stream
# @return string
#
function STDERR () {

cat - 1>&2

}

# remove the directory /bubu
if rm /bubu 2>/dev/null; then
    echo "Bubu is gone."
else
    echo "Has anyone seen Bubu?" | STDERR
fi


# run the bubu.sh and redirect you output
tux@earth:~$ ./bubu.sh >/tmp/bubu.log 2>/tmp/bubu.err
erselbst
la source
2
Je pense que vous pouvez faire la même chose avec l'alias et être beaucoup plus compact
BCS
ou vous pouvez simplement echo what | /dev/stderr
diriger
11

Remarque: je réponds à la question - pas à la question "écho trompeur / vague qui sort vers stderr" (déjà répondu par OP).

Utilisez une fonction pour montrer l' intention et source l'implémentation que vous souhaitez. Par exemple

#!/bin/bash

[ -x error_handling ] && . error_handling

filename="foobar.txt"
config_error $filename "invalid value!"

output_xml_error "No such account"

debug_output "Skipping cache"

log_error "Timeout downloading archive"

notify_admin "Out of disk space!"

fatal "failed to open logger!"

Et error_handlingétant:

ADMIN_EMAIL=root@localhost

config_error() { filename="$1"; shift; echo "Config error in $filename: $*" 2>&1; }

output_xml_error() { echo "<error>$*</error>" 2>&1; }

debug_output() { [ "$DEBUG"=="1" ] && echo "DEBUG: $*"; }

log_error() { logger -s "$*"; }

fatal() { which logger >/dev/null && logger -s "FATAL: $*" || echo "FATAL: $*"; exit 100; }

notify_admin() { echo "$*" | mail -s "Error from script" "$ADMIN_EMAIL"; }

Raisons qui gèrent les préoccupations du PO:

  • syntaxe la plus agréable possible (mots significatifs au lieu de symboles laids)
  • plus difficile de faire une erreur (surtout si vous réutilisez le script)
  • ce n'est pas un outil Bash standard, mais il peut s'agir d'une bibliothèque shell standard pour vous ou votre entreprise / organisation

Autres raisons:

  • clarté - montre l'intention aux autres responsables
  • vitesse - les fonctions sont plus rapides que les scripts shell
  • réutilisabilité - une fonction peut appeler une autre fonction
  • configurabilité - pas besoin de modifier le script d'origine
  • débogage - plus facile de trouver la ligne responsable d'une erreur (surtout si vous vous trompez avec une tonne de sortie de redirection / filtrage)
  • robustesse - si une fonction est manquante et que vous ne pouvez pas modifier le script, vous pouvez revenir à l'utilisation d'un outil externe du même nom (par exemple, log_error peut être aliasé dans logger sous Linux)
  • changer d'implémentation - vous pouvez passer à des outils externes en supprimant l'attribut "x" de la bibliothèque
  • sortie agnostique - vous n'avez plus à vous soucier si elle va à STDERR ou ailleurs
  • personnalisation - vous pouvez configurer le comportement avec des variables d'environnement
Cezary Baginski
la source
10

Ma suggestion:

echo "my errz" >> /proc/self/fd/2

ou

echo "my errz" >> /dev/stderr

echo "my errz" > /proc/self/fd/2aura pour effet de sortie , stderrcar /proc/selfun lien vers le processus en cours, et /proc/self/fdmaintient le processus descripteurs de fichiers ouverts, puis, 0, 1et 2reposer stdin, stdoutetstderr respectivement.

Le /proc/selflien ne fonctionne pas sur MacOS, cependant, /proc/self/fd/*est disponible sur Termux sur Android, mais pas /dev/stderr. Comment détecter le système d'exploitation à partir d'un script Bash? peut vous aider si vous devez rendre votre script plus portable en déterminant la variante à utiliser.

Sébastien
la source
5
Le /proc/selflien ne fonctionne pas sur MacOS, donc je vais m'en tenir à la /dev/stderrméthode la plus simple . En outre, comme indiqué dans d'autres réponses / commentaires, il est probablement préférable d'utiliser >>pour ajouter.
MarkHu
4
/proc/self/fd/*est disponible sur Termux sur Android, mais pas /dev/stderr.
go2null
9

Ne pas utiliser catcar certains sont mentionnés ici. catest un programme while echoet printfsont intégrés à bash (shell). Lancer un programme ou un autre script (également mentionné ci-dessus) signifie créer un nouveau processus avec tous ses coûts. En utilisant les fonctions intégrées, les fonctions d'écriture sont assez bon marché, car il n'est pas nécessaire de créer (exécuter) un processus (-environnement).

L'opner demande "existe-t-il un outil standard pour sortir ( pipe ) vers stderr", la réponse de schort est: NON ... pourquoi? ... rediriger les tuyaux est un concept élémentaire dans des systèmes comme unix (Linux ...) et bash (sh) s'appuie sur ces concepts.

Je suis d'accord avec l'ouvreur que la redirection avec des notations comme celle-ci: &2>1n'est pas très agréable pour les programmeurs modernes, mais c'est bash. Bash n'était pas destiné à écrire des programmes énormes et robustes, il est destiné à aider les administrateurs à y travailler avec moins de touches ;-)

Et au moins, vous pouvez placer la redirection n'importe où dans la ligne:

$ echo This message >&2 goes to stderr 
This message goes to stderr
retour42
la source
1
Dire aux développeurs de ne pas utiliser les programmes uniquement pour des raisons de performances est une optimisation prématurée. Les approches élégantes et faciles à suivre devraient être préférées aux codes difficiles à comprendre qui fonctionnent mieux (de l'ordre des millisecondes).
GuyPaddock
@GuyPaddock désolé, vous ne l'avez pas lu correctement. Sapins; Il s'agit de rediriger les tuyaux qui est bien géré par le bash. Si l'on n'aime pas la syntaxe (laide) de la façon dont bash redirige, il doit arrêter d'implémenter des scripts bash ou apprendre la méthode bash. Seconde; vous devez savoir à quel point il est coûteux de lancer un nouveau processus par rapport à un simple appel à bash.
return42
1
Il y a une différence entre faire savoir à quelqu'un les compromis de performances des Bash intégrés catet demander à quelqu'un de ne pas utiliser cat parce qu'il est lent. Il existe d'innombrables cas d'utilisation où le chat est le bon choix, c'est pourquoi je m'oppose à votre réponse.
GuyPaddock
@GuyPaddock L'ouvreur a demandé un echoremplacement. Même s'il utilise cat, il doit utiliser une redirection bash. en tous cas. Donc, il n'y a absolument aucun sens à utiliser catici. BTW J'utilise cat100 fois par jour, mais jamais dans le contexte que l'ouvreur a demandé ... tu l'as compris?
return42
8

Une autre option sur laquelle j'ai récemment trébuché est la suivante:

    {
        echo "First error line"
        echo "Second error line"
        echo "Third error line"
    } >&2

Cela n'utilise que les Bash intégrés tout en rendant la sortie d'erreur multi-lignes moins sujette aux erreurs (puisque vous n'avez pas à vous rappeler d'ajouter &>2à chaque ligne).

GuyPaddock
la source
1
Je ne peux pas le croire, vous me votez contre quand je recommande d'utiliser bash-redirect et dans votre propre réponse, vous utilisez bash-redirect.
return42
1
@ return42 J'ai voté contre votre réponse parce que tout ce qu'elle a fait, c'est de dire au PO qu'il n'y a pas de meilleure réponse que celle avec laquelle il a commencé .. ce n'est pas vraiment une réponse. Je ne vois pas non plus de suggestion de sous-shell dans votre réponse ... votre réponse conseille vraiment au PO de ne pas utiliser catou tout autre utilitaire, ce qui est hors sujet pour la question.
GuyPaddock
6

read est une commande intégrée au shell qui imprime sur stderr et peut être utilisée comme echo sans effectuer de trucs de redirection:

read -t 0.1 -p "This will be sent to stderr"

Le -t 0.1est un timeout qui désactive la fonctionnalité principale de read, stockant une ligne de stdin dans une variable.

Douglas Mayle
la source
5
Bash sur OS X ne permet pas le "0,1"
James Roth
2

Faire un script

#!/bin/sh
echo $* 1>&2

ce serait votre outil.

Ou créez une fonction si vous ne voulez pas avoir un script dans un fichier séparé.

n0rd
la source
6
Mieux vaut que ce soit une fonction (comme la réponse de James Roth), et mieux vaut transmettre tous les arguments, pas seulement le premier.
Cascabel
2
Pourquoi une fonction serait-elle meilleure? (Ou, alternativement: "Mieux vaut expliquer pourquoi il vaudrait mieux ...")
Psaume Ogre33
3
@ OgrePsalm33 L'une des raisons pour lesquelles une fonction serait meilleure est que lors de l'appel d'un script, une nouvelle instance de shell est généralement créée pour fournir un environnement dans lequel exécuter le script. Une fonction, d'autre part, est placée dans l'environnement du shell en cours d'exécution. L'appel d'une fonction, dans ce cas, serait une opération beaucoup plus efficace car la création d'une autre instance d'un shell serait évitée.
destenson
0

Solution de combinaison suggérée par James Roth et Glenn Jackman

  • ajoutez un code couleur ANSI pour afficher le message d'erreur en rouge:
echoerr() { printf "\e[31;1m%s\e[0m\n" "$*" >&2; }

# if somehow \e is not working on your terminal, use \u001b instead
# echoerr() { printf "\u001b[31;1m%s\u001b[0m\n" "$*" >&2; }

echoerr "This error message should be RED"
Polymérase
la source
-10

Mac OS X: J'ai essayé la réponse acceptée et quelques autres réponses et toutes ont abouti à l'écriture de STDOUT et non de STDERR sur mon Mac.

Voici une façon portable d'écrire sur une erreur standard en utilisant Perl:

echo WARNING! | perl -ne 'print STDERR'
Noah Sussman
la source
lol downvote tout ce que vous voulez, mais c'est la solution que j'utilise réellement dans mon code!
Noah Sussman