Der Grund, warum Sie keine Umleitung durch Erweitern verursachen können, "$HideErrors"
ist, dass Symbole wie >
nicht speziell behandelt werden, nachdem sie durch Parametererweiterung erstellt wurden . Dies ist tatsächlich sehr gut, da solche Symbole in Text enthalten sind, den Sie möglicherweise erweitern und wörtlich verwenden möchten.
Dies gilt unabhängig davon, ob Sie zitieren oder nicht $HideErrors
. Das Ergebnis der Parametererweiterung unterliegt der Wortteilung und dem Globbing, wenn die Erweiterung nicht in Anführungszeichen gesetzt ist, aber das war's.
Es gibt zahlreiche Möglichkeiten, eine bedingte Umleitung zu erreichen. Für einen sehr einfachen Befehl, kann es den ganzen Befehl zweimal angemessene Schreib sein, einmal in jedem Zweig eines case
oder if
- else
Konstrukt. Dies wird jedoch bald lästig, und der Befehl, den Sie gezeigt haben, ist sicherlich ein Fall, in dem dies nicht ideal wäre.
Von den Ansätzen, mit denen Sie vermeiden können, sich zu wiederholen , sind zwei besonders zu empfehlen, da sie recht sauber und leicht zu finden sind. Sie möchten nur einen dieser Befehle verwenden, nicht beide gleichzeitig für denselben Befehl und dieselbe Umleitung.
Speichern Sie den Befehl anstelle der Umleitung. Anstatt zu versuchen, die Umleitung in einer Variablen zu speichern und die Parametererweiterung anzuwenden, speichern Sie den Befehl in einer Shell-Funktion . Dann schreiben Sie ein case
oder if
- else
, in dem die Funktion mit der Umleitung auf einen Zweig und ohne auf den anderen Zweig aufgerufen wird.
Wenn Sie Ihren Befehl als Code konzipieren, den Sie einmal schreiben, aber unter mehreren Umständen ausführen möchten, ist eine Funktion die natürliche Lösung. Das ist was ich normalerweise tue. Es hat den Vorteil, dass weder eine Unterschale noch ein manuelles Speichern und Zurücksetzen des Zustands erforderlich sind .
Mit deinem Code:
launch() {
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName"
}
case $fCron in
true) launch 2>/dev/null;;
*) launch;; # Get silly error messages when running from terminal
esac
Sie können einen beliebigen Abstand verwenden oder if
- else
wenn Sie möchten - einen anderen. Beachten Sie, dass launch
der Aufrufer RobWebAddress
und die DownloadName
Variablen automatisch verwendet werden, auch wenn es sich um lokale Variablen handelt, da Bash im Gegensatz zu den meisten lexikalischen Programmiersprachen einen dynamischen Gültigkeitsbereich hat.
Führen Sie den Befehl in einer Subshell aus und wenden Sie die Umleitung unter bestimmten Bedingungen auf an exec
. Dies ist, was Stahlfahrer kommentierte , aber innen (
)
, um den Effekt lokal zu halten . Wenn das exec
Builtin ohne Argumente ausgeführt wird, ersetzt es die aktuelle Shell nicht durch einen neuen Prozess, sondern wendet stattdessen eine der Umleitungen auf die aktuelle Shell an.
(Es ist auch möglich, den Stand des Standardfehlers zu verfolgen und ihn wiederherzustellen, ohne eine Subshell zu verwenden und damit die Fähigkeit zu verlieren, die aktuelle Shell-Umgebung zu ändern. Die Details dazu überlasse ich jedoch anderen Antworten.)
Mit deinem Code:
(
# Suppress silly error messages unless running from terminal
case $fCron in true) exec 2>/dev/null;; esac
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName"
)
Nach dem Schließen )
wird der Standardfehler auf den vorherigen Stand zurückgesetzt, da er nur in der Subshell und nicht in der übergeordneten Shell umgeleitet wird. Auch dies funktioniert problemlos mit den vorhandenen Shell-Variablen, da Subshells eine Kopie davon erhalten. Obwohl ich lieber eine Shell-Funktion verwende, muss ich zugeben, dass für diese Methode möglicherweise weniger Code erforderlich ist.
Beide Methoden funktionieren unabhängig davon, als welcher Datei- oder Gerätestandardfehler gestartet wird, einschließlich im Fall von Umleitungen, die auf Shell-Funktionen angewendet werden, die den Code aufrufen, der das bedingte Verhalten enthält, sowie im Fall (in Ihrer Bearbeitung erwähnt), in dem Standardfehler für Das gesamte Skript wurde bereits von einem vorherigen oder umgeleitet . Dass der Weg durch Prozesssubstitution entstanden ist, ist kein Problem.exec 2>&fd
exec 2> path
[[ $fCron == true ]] && exec 2>/dev/null
stattdessen versuchen