Pumpenbefehlsausgabe als Funktionsargument

Pumpenbefehlsausgabe als Funktionsargument

Ich habe diese extrem einfache Funktion in meinem Skript:

# Used for debug tracing.
log()
{
    :
    echo "log: $1"
}

Die Idee besteht darin, die Protokollierung an einer einzigen Stelle anpassen/deaktivieren zu können. Sehr grob.

Jetzt möchte ich, dass mein Skript in der Release-Konfiguration absolut keine Ausgabe erzeugt. Die einzige Lösung, die mir eingefallen ist, aber äußerst unDRY:

TMPFILE='/tmp/tempfilewithpossiblyuniquename'
cmd 1>"$TMPFILE" 2>"$TMPFILE"
cat "$TMPFILE" | xargs log
rm "$TMPFILE"

fürjeder einzelne Befehl. Wie kann man das verbessern?


EDIT: Ich möchte sammelnalleAusgabe an stdoutund stderrund durchleiten log(). Dann log()können Sie wählen, ob Sie alles ignorieren, in eine Datei protokollieren, drucken usw. möchten.

Antwort1

Erstens protokolliert diese Funktion nur das erste „Wort“ aller an sie gesendeten Informationen, da Sie $1anstelle von verwenden "$*".

Zweitens gibt es (wie so oft bei POSIX) unzählige Möglichkeiten, so etwas zu tun. Ich würde wahrscheinlich etwas wie Folgendes wählen:

log() {
    cat - >> "$logfile"
}

do_stuff | log

Sie könnten aber auch:

(
    do_stuff
    do_more_stuff
) >> "$logfile"

Was das vollständige Unterdrücken aller Ausgaben betrifft, so ist dies normalerweise etwas, das man am besten der aufrufenden Umgebung überlässt (z. B. ./thing 1> /dev/null 2> &1), anstatt es sozusagen „im Code“ zu sperren. Das heißt:

squashout="true"  # comment this out to stop killing output
if ! [[ "true" = "${squashout-false}" ]]; then 
  # Redirect stdout and stderr to the null device.  
  exec 1> /dev/null
  exec 2> /dev/null
fi

Antwort2

Es ist einfach, absolut keine Ausgabe zu erstellen. Leiten Sie die Skripts einfach stdoutum stderrnach /dev/null:

exec >/dev/null 2>&1

Dies wirkt sich auf die Shell selbst und alle Befehle aus, die sie anschließend ausführt. Führen Sie dies bedingt aus, um auszuwählen, wohin die Ausgabe umgeleitet wird.

if [ "$output_to_file" = 1 ]; then
    exec > "$outputfilename" 2>&1
elif [ "$output_suppress" = 1 ]; then
    exec > /dev/null 2>&1
fi

Beachten Sie, dass das UnterdrückenalleAusgabe ist wahrscheinlich keine gute Idee. Der Benutzer möchte sehr wahrscheinlichmancheBenachrichtigung bei Fehlern.


Wenn Sie darauf bestehen, die Ausgabe durch die Funktion zu übergeben (und Bash/ksh/Zsh ausführen), können Sie die Prozesssubstitution verwenden:

#!/bin/bash
mangle_output() {
    # do something smarter here
    while read -r line; do
        echo "output: $line";
    done;
}
# redirect stdout and stderr to the function
exec > >(mangle_output) 2>&1
echo something that produces output

Beachten Sie jedoch, dass die Verarbeitung der Ausgabe mit einer Shell-Schleife keine gute Idee ist, zumindest ist es langsam. Siehe:Warum gilt die Verwendung einer Shell-Schleife zur Textverarbeitung als schlechte Praxis?. Wenn Sie lediglich eine Datei oder zu umleiten möchten /dev/null, verwenden Sie einfach execzum Einrichten von Umleitungen.

verwandte Informationen