Il motivo per cui non è possibile provocare il reindirizzamento espandendosi "$HideErrors"
è che simboli come >
non vengono trattati in modo speciale dopo essere stati prodotti dall'espansione dei parametri . Questo è in realtà molto buono, perché tali simboli appaiono nel testo che potresti voler espandere e usare letteralmente.
Questo vale se citate o meno $HideErrors
. Il risultato dell'espansione dei parametri è soggetto alla suddivisione delle parole e al globbing quando l'espansione non è quotata, ma il gioco è fatto.
Per quanto riguarda cosa fare al riguardo, ci sono numerosi modi per ottenere il reindirizzamento condizionale. Per un comando molto semplice, può essere ragionevole scrittura tutta comando due volte, una volta in ogni ramo di un case
o if
- else
costrutto. Questo diventa presto oneroso, tuttavia, e il comando che hai mostrato è certamente un caso in cui non sarebbe l'ideale.
Degli approcci che ti consentono di evitare di ripeterti , ce ne sono due che raccomando in particolare, perché sono abbastanza puliti e facili da ottenere. Vorresti usare solo uno di questi, non entrambi contemporaneamente per lo stesso comando e reindirizzamento.
Memorizza il comando anziché il reindirizzamento. Invece di tentare di memorizzare il reindirizzamento in una variabile e applicare l'espansione dei parametri, memorizzare il comando in una funzione shell . Quindi scrivere un case
o if
- else
, in cui la funzione viene chiamata con il reindirizzamento su un ramo e senza di essa sull'altro.
Se concettualizzi il tuo comando come codice che vuoi scrivere una volta ma eseguito in più circostanze, una funzione è la soluzione naturale. Questo è quello che faccio di solito. Ha il vantaggio di non richiedere né una subshell né una memorizzazione manuale e il ripristino dello stato.
Con il tuo codice:
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
Puoi applicare la spaziatura che preferisci o if
, else
invece, se preferisci. Nota che launch
usa automaticamente il chiamante RobWebAddress
e le DownloadName
variabili, anche se sono variabili locali, perché Bash ha un ambito dinamico , a differenza della maggior parte dei linguaggi di programmazione che hanno un ambito lessicale.
Esegui il comando in una subshell e applica condizionalmente il reindirizzamento a exec
. Questo è ciò di cui Steeldriver ha commentato , ma all'interno (
)
per mantenere l'effetto locale . Quando il exec
comando incorporato viene eseguito senza argomenti, non sostituisce la shell corrente con un nuovo processo, ma applica invece i suoi reindirizzamenti alla shell corrente.
(È anche possibile tenere traccia dell'errore standard e ripristinarlo, senza utilizzare una subshell e quindi senza sacrificare la possibilità di modificare l'ambiente della shell corrente. Tuttavia, lascerò i dettagli di questo ad altre risposte.)
Con il tuo codice:
(
# 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"
)
Dopo la chiusura )
, l'errore standard viene in effetti ripristinato su qualsiasi cosa fosse prima, perché viene realmente reindirizzato solo nella subshell e non nella shell genitore. Anche questo funziona bene con le variabili shell esistenti, poiché i subshells ne ottengono una copia. Anche se preferisco usare una funzione di shell, ammetto che questo metodo potrebbe richiedere meno codice.
Entrambi i metodi funzionano indipendentemente dall'errore standard del file o del dispositivo, incluso nel caso di reindirizzamenti applicati alle funzioni della shell che chiamano il codice che contiene il comportamento condizionale, nonché il caso (menzionato nella modifica) in cui l'errore standard per l'intero script è già stato reindirizzato da un precedente o . Che il percorso sia stato prodotto dalla sostituzione del processo non è un problema.exec 2>&fd
exec 2> path
[[ $fCron == true ]] && exec 2>/dev/null
invece provare