O motivo pelo qual você não pode causar o redirecionamento ao expandir "$HideErrors"
é que símbolos como >
não são tratados especialmente após serem produzidos pela expansão de parâmetros . Isso é realmente muito bom, porque esses símbolos aparecem no texto que você pode querer expandir e usar literalmente.
Isso vale se você citar ou não $HideErrors
. O resultado da expansão de parâmetros está sujeito à divisão e globbing de palavras quando a expansão não é citada, mas é isso.
Quanto ao que fazer sobre isso, existem várias maneiras de obter o redirecionamento condicional. Para um comando muito simples, pode ser razoável escrever o comando inteiro duas vezes, uma vez em cada ramo de uma construção - case
ou . Isso logo se torna oneroso, no entanto, e o comando que você mostrou é certamente um caso em que isso não seria o ideal.if
else
Das abordagens que permitem que você evite se repetir , há duas que eu recomendo especialmente, porque são bastante limpas e fáceis de acertar. Você deseja usar apenas um desses, não os dois ao mesmo tempo para o mesmo comando e redirecionamento.
Armazene o comando em vez do redirecionamento. Em vez de tentar armazenar o redirecionamento em uma variável e aplicar a expansão de parâmetros, armazene o comando em uma função shell . Em seguida, escreva um case
ou if
- else
, no qual a função é chamada com o redirecionamento em uma ramificação e sem ela na outra.
Se você conceituar seu comando como código que deseja escrever uma vez, mas executado sob várias circunstâncias, uma função é a solução natural. Isto é o que eu costumo fazer. Ele tem o benefício de não exigir um subconjunto nem armazenamento manual e redefinição de estado.
Com o seu código:
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
Você pode aplicar o espaçamento que quiser, ou if
- else
se preferir. Observe que launch
usa automaticamente o chamador RobWebAddress
e as DownloadName
variáveis, mesmo que sejam variáveis locais, porque o Bash tem escopo dinâmico , diferentemente da maioria das linguagens de programação com escopo lexical.
Execute o comando em uma subshell e aplique condicionalmente o redirecionamento exec
. Foi sobre isso que a steeldriver comentou , mas por dentro (
)
para manter o efeito local . Quando o exec
builtin é executado sem argumentos, ele não substitui o shell atual por um novo processo, mas aplica qualquer um de seus redirecionamentos ao shell atual.
(Também é possível acompanhar o que era o erro padrão e restaurá-lo, sem usar um subshell e, portanto, sem sacrificar a capacidade de modificar o ambiente do shell atual. Entretanto, deixarei os detalhes disso para outras respostas.)
Com o seu código:
(
# 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"
)
Após o fechamento )
, o erro padrão é efetivamente restaurado para o que era antes, porque está realmente sendo redirecionado apenas no subshell, e não no shell pai. Isso também funciona bem com as variáveis de shell existentes, pois os subshells recebem uma cópia delas. Embora prefira usar uma função shell, admito que esse método possa exigir menos código.
Ambos os métodos funcionam independentemente de qual erro padrão de arquivo ou dispositivo inicia, inclusive no caso de redirecionamentos aplicados a funções de shell que chamam o código que contém o comportamento condicional, bem como no caso (mencionado em sua edição) em que o erro padrão para o script inteiro já foi redirecionado por um ou anterior . Que o caminho foi produzido pela substituição do processo não é problema.exec 2>&fd
exec 2> path
[[ $fCron == true ]] && exec 2>/dev/null
em vez