Я хотел бы сформировать конвейерный поток, который захватывает stdout в один файл и stderr в другой файл И оба в третий файл (чтобы полный вывод терминала был в одном файле)
Ну вот как то так:
process ----+-- <stdout> --- + --- stdlog.txt
| |
| }---- <terminal> --- alllog.txt
| |
\-- <stderr> --- +---- errlog.txt
Я знаю, что мне нужно использовать tee, но я не могу понять. У вас есть решение? Предпочтительнее Bash/sh...
Спасибо за любую помощь, я действительно это ценю!!!
решение1
Во-первых: я бы вам этого не рекомендовал. Добавление временных меток и меток, таких как [INFO] и [ERROR], к зарегистрированным сообщениям в одном файле или просто временных меток в двух файлах, вероятно, будет лучшей и более надежной идеей в долгосрочной перспективе. При этом вы по-прежнему сможете создать другой нужный вам файл с помощью grep или сортировки.
По вашей проблеме: мне никогда не приходилось этого делать, но вам, вероятно, нужно использовать именованные каналы. Непроверенный пример bash:
# 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)
У вас может возникнуть соблазн использовать exec >"$info_pipe" 2>"$error_pipe"
. Не делайте этого, иначе вы создадите цикл, который заполнит все доступное дисковое пространство вашим файлом журнала.
Обратите внимание, что если ваш bash не поддерживает неявные именованные каналы (должен, но я видел среды, в которых этого не было), вы можете использовать их явно, вызвав mkfifo, однако для этого потребуется больше усилий:
# 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