Eu tenho esse código que funciona:
# Hide irrelevant errors so chrome doesn't email us in cron
if [[ $fCron == true ]] ; then
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName" 2>/dev/null
else
# Get silly error messages when running from terminal
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName"
fi
Se eu tentar encurtar assim:
# Hide irrelevant errors so chrome doesn't email us in cron
local HideErrors
[[ $fCron == true ]] && HideErrors="2>/dev/null"
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName" "$HideErrors"
Recebo mensagens de erro:
[0826/043058.634775:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
[0826/043058.672587:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
[0826/043058.711640:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
(... SNIP ...)
Por que um argumento codificado funciona, mas não um argumento como variável?
Edição 2:
Atualmente, obtive sucesso com a sugestão alternativa da segunda resposta:
# Redirect errors when cron is used to /dev/null to reduce emails
ErrorPipe=/dev/stderr
[[ $fCron == true ]] && ErrorPipe=/dev/null
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName" 2>"$ErrorPipe"
Editar 1:
Com base na primeira resposta, devo salientar que o cabeçalho do programa já contém:
[[ $fCron != true ]] &&
exec 2> >(grep -v 'GtkDialog mapped without a transient parent' >&2)
A razão pela qual você não pode causar redirecionamento ao expandir
"$HideErrors"
é que símbolos como>
não são tratados especialmente depois de serem produzidos pela expansão de parâmetro . Isso é realmente muito bom, porque esses símbolos aparecem no texto que você pode querer expandir e usar literalmente.Isso vale independentemente de você citar ou não
$HideErrors
. O resultado da expansão de parâmetros está sujeito a divisão de palavras e globbing quando a expansão não está entre aspas, mas é isso.Quanto ao que fazer a respeito, 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
ouif
-else
. Isso logo se torna oneroso, no entanto, e o comando que você mostrou é certamente um caso em que isso não seria o ideal.Das abordagens que permitem evitar a repetição , há duas que recomendo especialmente, porque são bastante limpas e fáceis de acertar. Você gostaria de usar apenas um deles, 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
ouif
-else
, no qual a função é chamada com o redirecionamento em um ramo e sem ele no outro.Se você conceituar seu comando como código que deseja escrever uma vez, mas executado em várias circunstâncias, uma função é a solução natural. Isso é o que eu costumo fazer. Ele tem o benefício de não exigir um subshell nem armazenamento manual e redefinição de estado.
Com seu código:
Você pode aplicar o espaçamento que quiser, ou
if
-else
se preferir. Observe que usa automaticamente as variáveis elaunch
do chamador , mesmo que sejam variáveis locais, porque o Bash tem escopo dinâmico , ao contrário da maioria das linguagens de programação que têm escopo lexical.RobWebAddress
DownloadName
Execute o comando em um subshell e aplique condicionalmente o redirecionamento para
exec
. Foi sobre isso que o steeldriver comentou , mas por dentro(
)
para manter o efeito local . Quando oexec
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 qual foi o erro padrão e restaurá-lo, sem usar um subshell e, portanto, sem sacrificar a capacidade de modificar o ambiente do shell atual. No entanto, deixarei os detalhes disso para outras respostas.)
Com seu código:
Após o fechamento
)
, o erro padrão é de fato restaurado para o que era antes, porque ele 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 obtêm uma cópia delas. Embora eu prefira usar uma função shell, admito que esse método pode exigir menos código.Ambos os métodos funcionam independentemente de como o erro padrão de arquivo ou dispositivo começa, inclusive no caso de redirecionamentos aplicados a funções de shell que chamam o código que contém o comportamento condicional, bem como o caso (mencionado em sua edição) em que erro padrão para todo o script já foi redirecionado por um arquivo anterior ou . Que o caminho foi produzido por substituição de processo não é problema.
exec 2>&fd
exec 2> path
Porque os itens de sintaxe não são interpretados a partir de valores de variáveis expandidas. Ou seja, expansão de variável não é o mesmo que substituir a referência de variável pelo texto da variável na linha de comando. (Coisas como
;
,|
,&&
e aspas etc. também não são especiais nos valores das variáveis.)O que você pode fazer é usar aliases ou usar a variável para manter apenas o destino do redirecionamento.
Os aliases são apenas uma substituição de texto, para que possam conter itens sintáticos, como operadores e palavras-chave. Em um script, você precisaria
shopt expand_aliases
, pois por padrão eles estão desabilitados em shells não interativos. Então, isso imprime2
(somente):(E você também pode
alias jos=if niin=then soj=fi
escrever todas as suas declarações if em finlandês. Tenho certeza de que qualquer pessoa que leia o roteiro adoraria você.)Como alternativa, escreva o redirecionamento sempre, mas controle apenas o destino com uma variável. Você precisará de um destino sem operação para o caso em que não deseja alterar para onde a saída vai,
masNa verdade, adicionar/dev/stderr
deve funcionar nesse caso.2> /dev/stderr
não é uma operação proibida por causa da maneira como o Linux trata os fd's abertos/proc/<pid>/fd
como independentes do original. Isso afeta o posicionamento da posição de gravação e atrapalha a saída se for para um arquivo normal.No entanto, deve funcionar no modo de acréscimo (ou se stderr for para um pipe ou para um terminal):
Então, para repetir:
2> /dev/stderr
pode quebrar.Título da pergunta: "Como passar 2>/dev/null como uma variável?" Isso pode realmente ser feito usando
eval
Então podemos reescrever como
Onde o acesso à variável indireta impede que a expansão aconteça muito cedo no restante da linha de comando.
Aspas duplas em variáveis funcionam bem.