Enviar saída bash -x para o arquivo de log sem interromper a saída padrão

12

Existe uma maneira de enviar as informações exibidas executando um script bash com a opção -x em um arquivo, sem alterar a saída padrão vista por um usuário executando o script?

Este é um recurso de depuração que eu gostaria de implementar em um script bash que usamos que muda frequentemente.

Muito apreciado.

desculpe doutor de rosa
fonte

Respostas:

21

A saída de -x vai para stderr, não stdout. Mas mesmo isso pode ser um problema - muitos scripts terão dependências funcionais do conteúdo do stderr e é meio confuso ter os fluxos de depuração e stderr misturados em alguns casos.

As versões do Bash> 4.1 oferecem uma solução diferente: a variável de ambiente BASH_XTRACEFD permite especificar um descritor de arquivo que será usado para enviar o fluxo de depuração. Pode ser um arquivo ou canal ou qualquer outra coisa que você queira.

# Use FD 19 to capture the debug stream caused by "set -x":
exec 19>/tmp/my-script.log
# Tell bash about it  (there's nothing special about 19, its arbitrary)
export BASH_XTRACEFD=19

# turn on the debug stream:
set -x

# run some commands:
cd /etc
find 
echo "Well, that was fun."

# Close the output:
set +x
exec 19>&-

# See what we got:
cat /tmp/my-script.log

Com um pouco mais de mexer, você pode fazer outras coisas - como fazer um 'tee' nos fluxos stdout e / ou stdin, e intercalar aqueles com a saída de depuração, para que seu log fique mais completo. Para obter mais detalhes, consulte /programming/3173131/redirect-copy-of-stdout-to-log-file-from-within-bash-script-itself .

A grande vantagem dessa abordagem sobre as alternativas é que você não está arriscando alterações no comportamento do seu script injetando a saída de depuração no stdout ou stderr.

Stabledog
fonte
Veja também aqui como encontrar um descritor de arquivo não utilizado para o arquivo.
27419 jarno
É necessário fechar o descritor de arquivo (ou seja, linha exec 19>&-)? Na minha experiência, é fechado automaticamente, quando o script termina.
jarno 27/10/19
1
O código mostrado acima não pressupõe que você esteja executando um script, ou por quanto tempo ele pode durar etc. É verdade que, se você fizer o que esse snippet está fazendo e colocá-lo em um script, o identificador do arquivo será ser fechado apenas porque todo o shell desaparece no final do script. Portanto, nesse caso de uso, você não precisa fechar estritamente o identificador. Mas, em geral, ao codificar em um recurso, é uma boa prática fechar o que você abriu, porque seu código pode ser usado em um contexto maior, em que é mais provável que o serviço de limpeza seja importante.
Stabledog
Por que você exporta BASH_XTRACEFD? Por que não apenas definir valor para isso?
28419 jarno
De qualquer forma, uma maneira alternativa de fechar o descritor de arquivo é definir um novo valor (por exemplo, nulo) para BASH_XTRACEFD ou desmarcá-lo.
28419 jarno
4

set -xnão envia nada para a saída padrão, então não há problema nisso. O que ele faz é gravar no erro padrão, que vai para o console por padrão.

O que você quer fazer é redirecionar o stdout para outro arquivo, assim:

/bin/sh -x /my/script/file 2>/my/log/file
mulher
fonte
1

Veja man tee.

Você o executa como tee commandname filenameele exibirá os comandos de saída stdoute os escreverá também filename.

Sven
fonte