Como redirecionar o erro para um arquivo?

5

Eu tenho este script simples que redireciona a saída e append para um arquivo.

filename="/home/ronnie/tmp/hello"

date=$(date)
echo "$date" >> $filename

Agora, suponhamos que eu altere date=$(date) para date= $(date) , o que gerará um erro.

Meu script modificado:

filename="/home/ronnie/tmp/hello"

date= $(date)
echo "$date" >> $filename 2>> $filename 
#Also tried echo "$date" >> $filename 2>&1

Eu estava pensando que o script acima irá redirecionar o erro test.sh: line 5: Fri: command not found para o arquivo hello , mas ele simplesmente insere uma nova linha no arquivo e o erro é impresso no meu stdout .

Minha versão bash:

ronnier@ronnie:~/tmp$ bash --version
GNU bash, version 4.2.24(1)-release (i686-pc-linux-gnu)

Então, para onde estou indo errado?

    
por ronnie 19.10.2012 / 14:25

2 respostas

8

A linha que causa o erro é date =$(date) , esse erro é enviado para stderr. Nesse estágio, você não está redirecionando o stderr para nenhum lugar. A linha subsequente envia stderr para $ filename, mas não é essa linha que causa o erro.

Uma das maneiras de obter o efeito desejado é executar o script e direcionar o stderr para algum outro lugar ao mesmo tempo.

./myscript 2>> errors.txt

nesse ponto, o arquivo errors.txt conterá seu erro.

Portanto, o problema é que a linha que gera o erro é um erro no próprio script, não um erro causado por um comando externo que o script chama e que tem sua saída redirecionada. ou seja, é a saída de script de nível superior que você precisa redirecionar.

    
por 19.10.2012 / 14:30
2

O shell emite uma mensagem de erro quando atinge a linha 5. O fluxo de erros do shell não é redirecionado neste momento.

Se você escrever date= $(date) 2>/dev/null , a mensagem “comando não encontrado” vem do shell, não do comando cujo fluxo de erro é redirecionado. Portanto, você ainda verá a mensagem de erro.

Para evitar ver a mensagem de erro, coloque o comando inteiro dentro de um grupo e redirecione o fluxo de erros de todo o grupo:

{ date= $(date); } 2>/dev/null

Com chaves, o comando ainda é executado no shell pai, portanto, ele pode alterar seu ambiente e outro estado (não que isso seja feito aqui). Você também pode colocar o comando em um corpo de função, ou em um subshell (comandos dentro de parênteses, que são executados em um processo de shell separado).

Você pode redirecionar os descritores de arquivo do shell permanentemente (ou pelo menos até a próxima vez que você os alterar) usando um redirecionamento no exec incorporado sem nome de comando.

exec 2>/dev/null
# From this point on, all error messages are lost
date= $(date)
…
exec 2>/some/log/file
# From this point on, all error messages go to the specified file
    
por 20.10.2012 / 00:10