Wie kann ich die Ausgabe nur unterdrücken, wenn der Befehl erfolgreich ist?


21

Ich möchte die Ausgabe eines Skripts vereinfachen, indem ich die Ausgabe von sekundären Befehlen unterdrücke, die normalerweise erfolgreich sind.

Doch mit -qversteckt auf sie den Ausgang , wenn sie gelegentlich fehlschlagen, so dass ich keine Möglichkeit , das Verständnis der Fehler haben. Darüber hinaus melden diese Befehle ihre Ausgabe an stderr.

Gibt es eine Möglichkeit, die Ausgabe eines Befehls nur dann zu unterdrücken, wenn dies erfolgreich ist ?

Zum Beispiel (aber nicht beschränkt auf) so etwas:

mycommand | fingerscrossed

Wenn alles gut geht, wird fingerscrosseddie Ausgabe abgefangen und verworfen. Andernfalls wird es an die Standard- oder Fehlerausgabe weitergegeben (was auch immer).

Antworten:


36

moreutils' chronicBefehl macht genau das:

chronic mycommand

schluckt mycommanddie Ausgabe, es sei denn, sie schlägt fehl. In diesem Fall wird die Ausgabe angezeigt.


1
Vielen Dank. Ich nehme an, es ist nicht standardmäßig auf den meisten Unix-Betriebssystemen installiert.
Matthieu Napoli

1
Wahrscheinlich nicht, obwohl es weit verbreitet ist und daher leicht zu installieren sein sollte.
Stephen Kitt

1
Debian hat es im Paket moreutils.
Trotzdem nett

6
Beachten Sie, dass die gesamte Ausgabe im Speicher gespeichert wird.
Stéphane Chazelas

1
@ StéphaneChazelas Dies ist wahrscheinlich der einzige Weg, um so etwas zu implementieren. Die Ausgabe muss gespeichert werden, während der Befehl ausgeführt wird, falls dies erforderlich ist.
Centimane

11
### do this bit once at the top of your script
divert=
exec 3<>"${divert:=$(mktmp)}" 4<>/dev/null
rm -- "$divert"; unset divert
### then do this bit as often as needed
command >&3 2>&3
cat <&3 >&"$(((RTN=$?)?2:4))"

Das sollte wahrscheinlich den Trick machen. Es puffert die Ausgabe von jedem commandin eine gelöschte temporäre Datei und siphoniert danach seine Ausgabe in entweder /dev/nulloder stderr, abhängig davon, ob sein Rückgabestatus nicht Null war oder nicht. Da die temporäre Datei vor der Zeit gelöscht wird, kann sie nicht von einem Prozess gelesen werden , aber die aktuell Shell und seine Kinder auf seiner Dateideskriptor (abgesehen von hinterhältigen /proc/$pid/fdSnoops mit dem entsprechenden Berechtigungen) , und es erfordert keine Reinigung , wenn Sie fertig sind.

Vielleicht eine bequemere Lösung für Linux-Systeme:

divert(){
    "$@" >&3 2>&3 ||
    eval "cat <&3
          return $?"
}   3<<"" 3<>/dev/fd/3

... , die in den meisten Schalen, ähnlich wie die andere arbeitet, mit der Ausnahme , dass Sie es wie nennen kann: divert some simple-command with args. Hüten Sie sich vor hohen Ausgabebefehlen in "$@", wenn auch für dash, yashoder einige andere Schalen , die mit Rohren hier-Dokumente zu tun - ich denke , es ist in diesen Schalen möglich sein kann , den Rohrpuffer zu füllen (bei einer Standard von rund 128kb auf Linuxen) und so Deadlock . Das ist nicht eine Sorge für sein sollte ksh, mksh, bash, zsh, oder die Bourne - Shell, obwohl - all jene tun im Grunde das Gleiche wie ich ausdrücklich oben mit exec.


9

Normalerweise gibt der Befehl im Fehlerfall Meldungen an aus, stderrsodass Sie die Aufgabe einfach unterdrücken könnenstdout

mycommand > /dev/null


Vielen Dank, aber wie ich in der Frage gesagt habe, protokollieren meine Befehle alle Ausgaben auf stderr(so hat es keine Auswirkung).
Matthieu Napoli

4

Um Ihre eigenen chronischen zu machen

my_chronic() {
  tmp=$(mktemp) || return # this will be the temp file w/ the output
  "$@"  > "$tmp" 2>&1 # this should run the command, respecting all arguments
  ret=$?
  [ "$ret" -eq 0 ] || cat "$tmp"  # if $? (the return of the last run command) is not zero, cat the temp file
  rm -f "$tmp"
  return "$ret" # return the exit status of the command
}

3

Ich mache so etwas in meinen Makefiles:

if (mycommand) &> mycommand.log; then 
  echo success 
else 
  c=$?; 
  echo;echo -e "Bad result from previous command, see mycommand.log for more details";echo;
  command_to_run_on_fail
  (exit $c)
fi

Wenn Sie das an Ihre Situation anpassen, können Sie Folgendes tun:

if ! (mycommand) &> mycommand.log; then 
  c=$?; 
  cat mycommand.log
  rm mycommand.log
  (exit $c)
fi

Also führt "if" den Befehl aus und leitet die Ausgabe an mycommand.log weiter. Wenn Sie stdout vs stdout vs whatever abfangen müssen, müssen Sie möglicherweise den Pipe-Befehl '&>' in '>' ändern. Wenn der Befehl fehlschlägt, erfassen Sie den Fehlercode, drucken Sie den Inhalt von mycommand.log aus, entfernen Sie mycommand.log und kehren Sie schließlich mit dem ursprünglichen Fehlercode zurück.

Ohne das (exit $ c) würden Sie mit dem Exit-Code zurückkehren, der mit dem übereinstimmt, was der Befehl 'rm' zurückgegeben hat.

Schließlich, wenn Sie einen Einzeiler wollen, würde so etwas funktionieren.

mycommand &> mycommand.log || cat mycommand.log; rm mycommand.log

2
Wickelst du wirklich deine Befehle / etc. in (...)so etwas? Weil es nichts Nützliches für dich tut, als zusätzliche Sub-Shells zu erzeugen.
Etan Reisner

@EtanReisner (exit $c)stellt ein $?, was Sie sonst nicht tun können. if ! (mycommand) &>xist bei der Umleitung sinnvoll, wenn der Befehl zB verwendet timeoder einen Shell-Fehler geben würde.
Michael Homer

@MichaelHomer - für diese Dinge gibt es { ; }die Locken ... obwohl exites ein wenig schwierig ist, zugegeben.
mikeserv

Wenn Sie in einem Makefile-Snippet versuchen, mit dem zuvor gespeicherten zu $?beenden, können Sie es einfach verwenden, exit $caber ja, in anderen Fällen (exit $?)hat es Wert (obwohl eine Shell-Funktion rret() { return $1; }im Allgemeinen besser wäre, würde ich argumentieren). Die Subshell für Befehle ist allerdings immer noch nicht wirklich, wie mikeserv anzeigte.
Etan Reisner

3

Ich fand gerade diese viel einfachere Antwort auf diese andere Frage :

output=`mycommand 2>&1` || echo $output

Klappt wunderbar!


Hinweis: Für meinen Anwendungsfall war dies eine viel einfachere Lösung (vermeiden Sie die Installation zusätzlicher Komponenten auf allen CI-Servern). Daher habe ich mich dafür entschieden, diese als akzeptiert zu markieren. YMMV.
Matthieu Napoli

Beachten Sie, dass, wenn Sie set -o xtrace in Ihrem Shell-Skript verwenden, die gesamte Ausgabe wieder vorhanden ist, wenn Sie die Details der Zuweisungsausgabe protokollieren = ... :-). In diesem Fall ist es wahrscheinlich besser, chronisch zu verwenden.
Jan-Philip Gehrcke
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.