Echo, das an stderr ausgegeben wird

1116

Gibt es ein Standard-Bash-Tool, das sich wie ein Echo verhält, aber eher an stderr als an stdout ausgibt?

Ich weiß, dass ich das kann, echo foo 1>&2aber es ist ein bisschen hässlich und, wie ich vermute, fehleranfällig (z. B. wird es eher falsch bearbeitet, wenn sich etwas ändert).

BCS
quelle
Siehe auch
Flow

Antworten:

1453

Sie könnten dies tun, was das Lesen erleichtert:

>&2 echo "error"

>&2kopiert den Dateideskriptor Nr. 2 in den Dateideskriptor Nr. 1. Nachdem diese Umleitung durchgeführt wurde, beziehen sich beide Dateideskriptoren auf dieselbe Datei: Der eine Dateideskriptor Nr. 2 bezog sich ursprünglich auf dieselbe . Weitere Informationen finden Sie im Bash Hackers Illustrated Redirection Tutorial .

Marco Aurelio
quelle
2
Ich habe diesen Trick vor einiger Zeit gelernt. Diese Seite enthält einige gute Informationen. tldp.org/LDP/abs/html/io-redirection.html
Marco Aurelio
46
@BCS Ich weiß nicht, ob ich ein aliasin einem Shell-Skript verwenden soll. Es wäre wahrscheinlich sicherer zu verwendenerrcho(){ >&2 echo $@; }
Braden Best
3
> & 2 wird normalerweise am Ende gesetzt. Dies wird funktionieren, aber es wird seltener verwendet
Iskren Ivov Chernev
159
In den fast 40 Jahren, in denen ich Unix-ähnliche Systeme verwendet habe, ist mir nie in den Sinn gekommen, dass Sie die Weiterleitung irgendwo anders als am Ende platzieren könnten. Wenn Sie es so nach vorne stellen, wird es viel offensichtlicher (oder "erleichtert das Lesen", wie @MarcoAurelio sagt). +1, um mir etwas Neues beizubringen.
Hephaistos
Zu Ihrer Information: Wenn Sie etwas formatieren oder etwas anderes tun möchten, als nur die Zeichenfolge wiederzugeben, müssen Sie die Umleitung zurück zum Ende verschieben. Zum Beispiel errcho(){ >&2 echo $@|pr -To5;}wird nicht funktionieren. Um so etwas zu tun, müssen Sie die Weiterleitung irgendwo nach der letzten Pipe platzieren, wie:errcho(){ echo $@|>&2 pr -To5;}
Jon Red
423

Sie können eine Funktion definieren:

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

Dies wäre schneller als ein Skript und hätte keine Abhängigkeiten.

Camilo Martins bash-spezifischer Vorschlag verwendet eine "Hier-Zeichenfolge" und druckt alles, was Sie an ihn übergeben, einschließlich der Argumente (-n), die das Echo normalerweise verschlucken würde:

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

Die Lösung von Glenn Jackman vermeidet auch das Problem des Schluckens von Argumenten:

echoerr() { printf "%s\n" "$*" >&2; }
James Roth
quelle
7
Ich muss sagen, dass Echo irgendwie unzuverlässig ist. echoerr -ne xtwird nicht "-ne xt" drucken. Besser dafür nutzen printf.
Camilo Martin
10
Oh, Sie können tatsächlich auch Katze verwenden:echoerr() { cat <<< "$@" 1>&2; }
Camilo Martin
2
Das war mir nicht bewusst. Hinzugefügt.
James Roth
4
Oderprintf "%s\n" "$*" >&2
Glenn Jackman
4
@GKFX Natürlich funktioniert es nur beim Zitieren richtig. Warum die Leute ihre Saiten nicht zitieren, ist mir ein Rätsel. (Wenn Sie nicht zitieren, wird alles, was durch ein oder mehrere $IFSLeerzeichen getrennt ist, als separates Argument gesendet, was im Fall von echoVerkettung mit 0x20s bedeutet, aber die Gefahren, nicht weit zu zitieren, übersteigen die Bequemlichkeit von 2 Zeichen weniger) .
Camilo Martin
252

Da 1es sich um die Standardausgabe handelt, müssen Sie diese nicht explizit vor einer Ausgabeumleitung wie benennen> sondern können einfach Folgendes eingeben:

echo Diese Nachricht geht an stderr> & 2

Da Sie sich Sorgen zu machen scheinen, dass 1>&2es für Sie schwierig sein wird, zuverlässig zu tippen, könnte die Beseitigung der Redundanz 1eine leichte Ermutigung für Sie sein!

Brandon Rhodes
quelle
59

Andere Option

echo foo >>/dev/stderr
Steven Penny
quelle
4
Ist diese Option portabel? Weiß jemand, ob dies für ein Unix-Aroma nicht funktioniert?
Dacav
7
Es funktioniert nicht in bestimmten Chroots, die nicht auf / dev / stderr zugreifen können.
Zachary Vance
12
Wenn das Skript, das diese Zeile ausführt - nennen wir es foo- einen eigenen stderr umgeleitet hat - z. B. foo >foo.log 2>&1-, echo foo >/dev/stderrwird die gesamte Ausgabe davor blockiert. >>sollte stattdessen verwendet werden:echo foo >>/dev/stderr
Doshea
Ebenso hast du /dev/fd/2.
Jbruni
@Dacav das ist sicher portabel : /proc/self/fd/2. Siehe meine Antwort unten :)
Sebastian
31

Nein, das ist die Standardmethode. Es sollte keine Fehler verursachen.

Matthew Flaschen
quelle
9
Es sollte keine Fehler verursachen, aber ich könnte eher. OTOH, es ist keine so große Sache.
BCS
6
@Mike DeSimone: Wenn jemand anderes mit dem Code herumspielt, durch die Ausgabe schlurft und Bash nicht wirklich kennt, kann er den Code leicht löschen (oder falsch eingeben) 1>&2. Wir alle wünschen uns, dass dies nicht passieren würde, aber ich bin sicher, wir waren alle Orte, an denen dies der Fall ist.
Cascabel
2
( echo something 1>&2 ; something else ) > log-> (echo something; cp some junk 1>&2 ; something else) > logUps.
BCS
29
IMHO, wenn jemand mit dem Code herumspielt und Bash nicht kennt, kann dies das geringste Ihrer Probleme sein.
Mike DeSimone
7
Ich denke, wenn das wahrscheinlich ein Problem ist, sollten Sie eine andere Sprache verwenden: Der Versuch, Bash narrensicher zu machen, ist ein Kinderspiel.
Intuitiert
17

Wenn es Ihnen nichts ausmacht, die Nachricht auch in syslog zu protokollieren, lautet der not_so_ugly-Weg:

logger -s $msg

Die Option -s bedeutet: "Ausgabe der Nachricht an Standardfehler sowie an das Systemprotokoll."

Grzegorz Luczywo
quelle
1
das ist toll! Wie tragbar ist es?
Code_Monk
@code_monk: Es wird erwartet, dass der Logger-Befehl IEEE Std 1003.2 ("POSIX.2") -kompatibel ist. Der Logger-Befehl ist Teil des util-linux-Pakets und im Linux-Kernel-Archiv ⟨kernel.org/ pub/linux/utils verfügbar / util-linux⟩ .
Miku
12

Dies ist eine einfache STDERR-Funktion, die den Pipe-Eingang zu STDERR umleitet.

#!/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
quelle
2
Ich denke, Sie können das gleiche mit Alias ​​tun und viel kompakter sein
BCS
oder Sie können einfach direkt zur Gerätedatei echo what | /dev/stderr
weiterleiten
11

Hinweis: Ich beantworte die Frage nach dem Post- und nicht dem irreführenden / vagen "Echo, das an stderr ausgegeben wird" (bereits von OP beantwortet).

Verwenden Sie eine Funktion, um die Absicht anzuzeigen und die gewünschte Implementierung zu erstellen. Z.B

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

Und error_handlingsein:

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"; }

Gründe, die Bedenken in OP behandeln:

  • schönste Syntax möglich (sinnvolle Wörter statt hässlicher Symbole)
  • Es ist schwieriger, einen Fehler zu machen (insbesondere, wenn Sie das Skript wiederverwenden).
  • Es ist kein Standard-Bash-Tool, aber es kann eine Standard-Shell-Bibliothek für Sie oder Ihr Unternehmen / Ihre Organisation sein

Andere Gründe:

  • Klarheit - zeigt anderen Betreuern die Absicht
  • Geschwindigkeit - Funktionen sind schneller als Shell-Skripte
  • Wiederverwendbarkeit - Eine Funktion kann eine andere Funktion aufrufen
  • Konfigurierbarkeit - Original-Skript muss nicht bearbeitet werden
  • Debugging - einfacher, die für einen Fehler verantwortliche Zeile zu finden (insbesondere, wenn Sie mit einer Menge Umleitungs- / Filterausgaben beschäftigt sind)
  • Robustheit - Wenn eine Funktion fehlt und Sie das Skript nicht bearbeiten können, können Sie auf die Verwendung eines externen Tools mit demselben Namen zurückgreifen (z. B. kann log_error unter Linux als Logger verwendet werden).
  • Implementieren wechseln - Sie können zu externen Tools wechseln, indem Sie das Attribut "x" der Bibliothek entfernen
  • Ausgabeunabhängig - Sie müssen sich nicht mehr darum kümmern, ob es an STDERR oder anderswo geht
  • Personalisierung - Sie können das Verhalten mit Umgebungsvariablen konfigurieren
Cezary Baginski
quelle
10

Mein Vorschlag:

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

oder

echo "my errz" >> /dev/stderr

echo "my errz" > /proc/self/fd/2effektiv ausgegeben wird , stderrweil /proc/selfein Link zu dem aktuellen Prozess, und /proc/self/fdhält den Prozess Filedeskriptoren geöffnet, und dann 0, 1und 2stehen für stdin, stdoutund stderrjeweils.

Der /proc/selfLink funktioniert unter MacOS nicht, ist jedoch /proc/self/fd/*unter Termux unter Android verfügbar, jedoch nicht /dev/stderr. Wie erkenne ich das Betriebssystem anhand eines Bash-Skripts? kann helfen, wenn Sie Ihr Skript portabler machen müssen, indem Sie bestimmen, welche Variante verwendet werden soll.

Sebastian
quelle
5
Der /proc/selfLink funktioniert unter MacOS nicht, daher bleibe ich bei der einfacheren /dev/stderrMethode. Wie in anderen Antworten / Kommentaren erwähnt, ist es wahrscheinlich besser, >>das Anhängen zu verwenden.
MarkHu
4
/proc/self/fd/*ist unter Termux unter Android verfügbar, aber nicht /dev/stderr.
go2null
9

Nicht verwenden, catda einige hier erwähnt werden. catist ein Programm während echound printfsind Bash (Shell) Builtins. Programm starten oder ein anderes Skript (ebenfalls oben erwähnt) starten, müssen Sie einen neuen Prozess mit allen Kosten erstellen. Mit eingebauten Funktionen sind Schreibfunktionen recht billig, da kein Prozess (-Umgebung) erstellt (ausgeführt) werden muss.

Der Opner fragt "Gibt es ein Standardwerkzeug für die Ausgabe ( Pipe ) an stderr?". Die kurze Antwort lautet: NEIN ... warum? ... das Umleiten von Pipes ist ein grundlegendes Konzept in Systemen wie Unix (Linux ...) und bash (sh), das auf diesen Konzepten aufbaut.

Ich stimme dem Opener zu, dass das Umleiten mit solchen Notationen &2>1für moderne Programmierer nicht sehr angenehm ist, aber das ist Bash. Bash sollte keine riesigen und robusten Programme schreiben, sondern den Administratoren helfen, mit weniger Tastendruck dorthin zu gelangen ;-)

Und zumindest können Sie die Umleitung an einer beliebigen Stelle in der Zeile platzieren:

$ echo This message >&2 goes to stderr 
This message goes to stderr
return42
quelle
1
Entwicklern zu sagen, dass sie Programme nicht nur aus Leistungsgründen verwenden sollen, ist eine vorzeitige Optimierung. Elegante, leicht zu verfolgende Ansätze sollten schwer verständlichem Code mit besserer Leistung (in der Größenordnung von Millisekunden) vorgezogen werden.
GuyPaddock
@ GuyPaddock Entschuldigung, Sie haben dies nicht richtig gelesen. Tannen; Es geht darum, Rohre umzuleiten, die von der Bash gut gehandhabt werden. Wenn jemand die (hässliche) Syntax, wie Bash umleitet, nicht mag, sollte er die Implementierung von Bash-Skripten einstellen oder den Bash-Weg lernen. Zweite; Sie sollten wissen, wie teuer es ist, einen neuen Prozess zu starten, anstatt nur eine eingebaute Bash zu nennen.
Rückkehr42
1
Es gibt einen Unterschied zwischen der Kenntnisnahme der Leistungskompromisse von Bash-Integrationen catund der Anweisung, keine Katze zu verwenden, da diese langsam ist. Es gibt unzählige Anwendungsfälle, in denen Katze die richtige Wahl ist. Deshalb lehne ich Ihre Antwort ab.
GuyPaddock
@GuyPaddock Der Öffner bat um einen echoErsatz. Selbst wenn er verwendet cat, muss er eine Bash-Weiterleitung verwenden. wie auch immer. Es macht also absolut keinen Sinn, cathier zu verwenden . Übrigens benutze ich cat100 Mal am Tag, aber nie in dem Kontext, nach dem der Opener gefragt hat ... hast du es verstanden?
Rückkehr42
8

Eine andere Option, über die ich kürzlich gestolpert bin, ist folgende:

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

Dies verwendet nur integrierte Bash-Funktionen, während die Ausgabe von mehrzeiligen Fehlern weniger fehleranfällig ist (da Sie nicht daran denken müssen &>2, jeder Zeile etwas hinzuzufügen ).

GuyPaddock
quelle
1
Ich kann es nicht glauben, Sie stimmen mich ab, wenn ich die Verwendung von Bash-Redirect empfehle, und in Ihrer eigenen Antwort verwenden Sie Bash-Redirect.
Rückkehr42
1
@ return42 Ich habe Ihre Antwort abgelehnt, weil es dem OP nur gesagt hat, dass es keine bessere Antwort gibt als die, mit der sie begonnen haben. Es ist nicht wirklich eine Antwort. Ich sehe auch keinen Sub-Shell-Vorschlag in Ihrer Antwort ... Ihre Antwort rät dem OP wirklich nur, catkein anderes Dienstprogramm zu verwenden, das für die Frage nicht zum Thema gehört.
GuyPaddock
6

read ist ein in die Shell integrierter Befehl, der auf stderr gedruckt wird und wie Echo verwendet werden kann, ohne Umleitungstricks auszuführen:

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

Das -t 0.1ist ein Timeout deaktiviert Hauptfunktionalität zu lesen, eine Zeile von stdin in eine Variable speichern.

Douglas Mayle
quelle
5
Bash unter OS X erlaubt nicht die "0.1"
James Roth
2

Mach ein Skript

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

das wäre dein Werkzeug.

Oder erstellen Sie eine Funktion, wenn Sie kein Skript in einer separaten Datei haben möchten.

n0rd
quelle
6
Besser, es ist eine Funktion (wie James Roths Antwort), und es ist besser, alle Argumente weiterzugeben, nicht nur die ersten.
Cascabel
2
Warum sollte eine Funktion besser sein? (Oder alternativ: "Besser erklären, warum es besser wäre ...")
Oger Psalm33
3
@ OgrePsalm33 Ein Grund, warum eine Funktion besser wäre, ist, dass beim Aufrufen eines Skripts normalerweise eine neue Shell-Instanz erstellt wird, um eine Umgebung bereitzustellen, in der das Skript ausgeführt werden kann. Eine Funktion wird dagegen in die aktuell ausgeführte Shell-Umgebung eingefügt. Das Aufrufen einer Funktion wäre in diesem Fall eine viel effizientere Operation, da das Erstellen einer anderen Instanz einer Shell vermieden würde.
Destenson
-10

Mac OS X: Ich habe die akzeptierte Antwort und einige andere Antworten ausprobiert und alle haben dazu geführt, dass STDOUT nicht STDERR auf meinem Mac geschrieben wurde.

Hier ist eine tragbare Möglichkeit, mit Perl auf Standardfehler zu schreiben:

echo WARNING! | perl -ne 'print STDERR'
Noah Sussman
quelle
lol stimme ab, was du willst, aber das ist die Lösung, die ich tatsächlich in meinem Code verwende!
Noah Sussman