Atualmente, uso a seguinte configuração para redirecionar a saída de vários comandos:
echo "Some normal commands"
(
echo "Error: something happened"
echo "Warning: this incident will be logged"
) >> logfile
echo "More normal commands"
Isso é bastante útil e também funciona com tubos.
Essa é a melhor maneira de fazer isso? Existe uma alternativa que eu deva considerar?
bash
shell-script
io-redirection
wchargin
fonte
fonte
:)
Respostas:
A alternativa é usar chaves em vez de parênteses. Essa alteração executa os comandos no shell atual , não em um subshell
ref: https://www.gnu.org/software/bash/manual/bashref.html#Command-Grouping
Isso é particularmente relevante quando você está modificando variáveis dentro do grupo:
fonte
{ }
( )
(echo msg1; echo msg2)
- mas, com chaves, deve ser{ echo msg1; echo msg2;}
, com um espaço após o{
ponto-e-vírgula (;
) ou um e comercial (&
) antes do}
.A resposta de Glenn é boa - a distinção entre
( ... )
e{ ... }
é importante.Uma estratégia que costumo usar para gerar erros como o que está em sua pergunta é o
tee
comando. Você poderia fazer algo assim:O
tee
comando enviará a saída para dois lugares;-a
A opção "anexa" a saída ao arquivo nomeado, e o comando também passará a entrada para o stdout. O>&2
no final da linha redirecionatee
o stdout do stderr, que pode ser tratado de maneira diferente (ou seja, em um trabalho cron).Uma outra dica que costumo usar em scripts de shell é alterar o comportamento da depuração ou saída detalhada, com base no fato de o script estar sendo executado em um terminal ou ter uma
-v
opção fornecida. Por exemplo:Os scripts podem começar com algo genérico como esse no topo, com a saída Verbose e Debug espalhadas por todo o script. É apenas uma maneira de fazer isso - existem muitos, e pessoas diferentes terão seu próprio jeito de lidar com essas coisas, especialmente se elas já existem há algum tempo. :)
Mais uma opção é manipular sua saída com um "manipulador" - uma função de shell que pode fazer coisas mais inteligentes. Por exemplo:
(Observe que
${var^^}
é apenas para o bash.)Isso cria uma função shell que pode usar as
syslog
funções do seu sistema (com ologger
comando) to send things to system logs. The
logme () `, a função pode ser usada com opções que geram linhas únicas de dados de log ou com várias linhas de entrada que são processadas no stdin. parece atraente.Observe que este é um exemplo e provavelmente não deve ser copiado literalmente, a menos que você o entenda e saiba que ele faz exatamente o que você precisa. Uma idéia melhor é pegar os conceitos aqui e implementá-los em seus próprios scripts.
fonte
function log () { cat >> $logfile }
, que é basicamente uma versão mais simples do seulogme
.ts(1)
; uso:{ printf '%s\n' "Warning text"; printf '%s\n' "This event will be logged"; } | ts '[%Y-%m-%d %T]' | tee -a "$logfile" >&2
.ts(1)
não está instalado nos sistemas que uso - FreeBSD, OSX e uma caixa antiga do Ubuntu. Você pode nos dizer o que fornece?sponge(1)
(gravar no arquivo somente depois que o stdin for fechado, para que você possa fazersomething < foo | sponge foo
evitar ofoo
redirecionamento) evipe(1)
(inserir um editor de texto em um canal).A maneira mais apropriada de fazer isso é com
{ command; }
e não(command)
. O motivo é que, quando os comandos são agrupados com()
um subshell, é aberto para executar esses comandos e, portanto, as variáveis inicializadas durante esse bloco não ficam disponíveis para outras seções do script.Em vez disso, quando usamos o
{}
agrupamento de comandos, os comandos são executados no mesmo shell e, portanto, as variáveis estarão disponíveis para outras seções do script.Aqui, quando esta seção é executada, a
$var
variável retém seu valor, e, como no outro caso, não.fonte
{ command; }
.