Eu gostaria de formar um pipe-stream que capture stdout para um arquivo e stderr para outro arquivo E ambos em um terceiro arquivo (assim também a saída completa do terminal está em um arquivo)
de alguma forma assim:
process ----+-- <stdout> --- + --- stdlog.txt
| |
| }---- <terminal> --- alllog.txt
| |
\-- <stderr> --- +---- errlog.txt
Eu sei que tenho que usar camiseta, mas não consigo descobrir. Vocês têm uma solução? Bash/sh preferido...
Obrigado por qualquer ajuda, eu realmente aprecio isso !!!
Responder1
Primeiro: não é algo que eu recomendo que você faça, anexar mensagens registradas com carimbos de data e hora e rótulos como [INFO] e [ERROR] em um único arquivo ou apenas carimbos de data e hora em seus dois arquivos provavelmente seria uma ideia melhor e mais confiável no longo prazo. enquanto ainda permite que você crie o outro arquivo desejado usando grep ou classificação.
Para o seu problema: nunca precisei fazer isso, mas provavelmente você precisará usar pipes nomeados. Exemplo de bash não testado:
# Log one output type
function logger() {
unique_file="$1"
common_file="$2"
# Tee reads from the function's standard input, writes to unique_file, appends to common_file, then outputs what was written
tee "$unique_file" | tee -a "$common_file"
}
# Call your code's main function to start processing
main > >(logger info_log_file common_log_file) 2> >(logger error_log_file common_log_file >&2)
Você pode ficar tentado a usar exec >"$info_pipe" 2>"$error_pipe"
. Não faça isso, ou você gerará um loop que fará com que seu arquivo de log preencha todo o espaço disponível em disco
Observe que se o seu bash não suporta pipes nomeados implícitos (deveria, mas já vi ambientes que não suportam), você pode querer usá-los explicitamente chamando mkfifo, no entanto, isso requer mais encanamento:
# Log one output type
function logger() {
unique_file="$1"
common_file="$2"
# Tee reads from the function's standard input, writes to unique_file, appends to common_file, then outputs what was written
tee "$unique_file" | tee -a "$common_file"
}
# Setup logging
function prepare() {
tmp_pipe_dir="$(mktemp -d)"
error_pipe="$(mkfifo "$tmp_pipe_dir/error")"
info_pipe="$(mkfifo "$tmp_pipe_dir/info")"
}
function cleanup() {
rm -rf "$tmp_pipe_dir"
}
prepare
# Start logging, note that logger won't stop on its own. Removing the pipe files should do the trick
logger info_log_file common_log_file <"$info_pipe" &
logger error_log_file common_log_file <"$error_pipe" >&2 &
# Call your code's main function to start processing
main >"$info_pipe" 2>"$error_pipe"
cleanup