Powodem, dla którego nie można spowodować przekierowania przez rozwinięcie, "$HideErrors"
jest to, że takie symbole >
nie są traktowane specjalnie po wytworzeniu przez rozwinięcie parametru . To jest naprawdę bardzo dobre, ponieważ takie symbole pojawiają się w tekście, który możesz chcieć rozwinąć i używać dosłownie.
Dotyczy to tego, czy zacytowałeś czy nie $HideErrors
. Wynik interpretacji parametrów podlega dzieleniu i globowaniu słów, gdy interpretacja nie jest cytowana , ale to wszystko.
Jeśli chodzi o to, co z tym zrobić, istnieje wiele sposobów osiągnięcia warunkowego przekierowania. Przez bardzo prostego polecenia, może być uzasadnione zapisem cała komenda dwa razy, raz w każdej gałęzi case
lub if
- else
konstruktem. Szybko staje się to jednak uciążliwe, a polecenie, które pokazałeś, z pewnością nie byłoby idealne.
Spośród metod, które pozwalają uniknąć powtarzania się , szczególnie polecam dwa, ponieważ są one dość czyste i łatwo je naprawić. Chciałbyś użyć tylko jednego z nich, a nie obu naraz dla tego samego polecenia i przekierowania.
Zapisz polecenie zamiast przekierowania. Zamiast próbować zapisać przekierowanie w zmiennej i zastosować rozszerzenie parametrów, zapisz polecenie w funkcji powłoki . Następnie napisz case
lub if
- else
, w którym funkcja jest wywoływana z przekierowaniem na jednym oddziale, a bez niego na drugim.
Jeśli konceptualizujesz swoje polecenie jako kod, który chcesz napisać raz, ale działa w wielu okolicznościach, funkcja jest naturalnym rozwiązaniem. Tak zwykle robię. Ma tę zaletę, że nie wymaga ani podpowłoki, ani ręcznego przechowywania i resetowania stanu.
Z twoim kodem:
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
Możesz zastosować dowolne odstępy lub if
- else
zamiast tego, jeśli wolisz. Zauważ, że launch
automatycznie używa wywołującego RobWebAddress
i DownloadName
zmiennych, nawet jeśli są to zmienne lokalne, ponieważ Bash ma zakres dynamiczny , w przeciwieństwie do większości języków programowania, które mają zasięg leksykalny.
Uruchom polecenie w podpowłoce i warunkowo zastosuj przekierowanie do exec
. O tym skomentował steeldriver , ale w środku, (
)
aby efekt był lokalny . Kiedy wbudowane jest uruchamiany bez argumentów, nie zastąpi obecny powłoki z nowego procesu, lecz stosuje się którykolwiek z jego przekierowań do bieżącej powłoki.exec
(Możliwe jest również śledzenie, jaki był standardowy błąd i przywrócenie go, bez użycia podpowłoki, a tym samym bez poświęcania możliwości modyfikowania bieżącego środowiska powłoki. Zostawię to jednak szczegółowi innym odpowiedziom.)
Z twoim kodem:
(
# 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"
)
Po zamknięciu )
standardowy błąd jest przywracany do poprzedniego stanu, ponieważ jest przekierowywany tylko w podpowłoce, a nie w powłoce nadrzędnej. To również działa dobrze z istniejącymi zmiennymi powłoki, ponieważ podpowłoki otrzymują ich kopię. Chociaż wolę używać funkcji powłoki, przyznaję, że ta metoda może wymagać mniej kodu.
Obie metody działają niezależnie od tego, jak zaczyna się standardowy błąd pliku lub urządzenia, w tym w przypadku przekierowań zastosowanych do funkcji powłoki, które wywołują kod zawierający zachowanie warunkowe, a także w przypadku (wymienionym w Twojej edycji), w którym błąd standardowy dla cały skrypt został już przekierowany przez poprzednią lub . To, że ścieżka została utworzona przez podstawienie procesu, nie stanowi problemu.exec 2>&fd
exec 2> path
[[ $fCron == true ]] && exec 2>/dev/null
zamiast tego