Я знаю, как использовать teeдля записи выходных данных ( STDOUT) aaa.shв bbb.out, при этом отображая его в терминале:
./aaa.sh | tee bbb.out
Как бы мне теперь записать STDERRфайл с именем ccc.out, пока он все еще отображается?
Я знаю, как использовать teeдля записи выходных данных ( STDOUT) aaa.shв bbb.out, при этом отображая его в терминале:
./aaa.sh | tee bbb.out
Как бы мне теперь записать STDERRфайл с именем ccc.out, пока он все еще отображается?
Ответы:
Я предполагаю, что вы все еще хотите видеть STDERR и STDOUT на терминале. Вы могли бы пойти за ответом Джоша Келли, но я нахожу tailв тени фон, который выводит ваш лог-файл очень хакерский и грязный. Обратите внимание, как вам нужно сохранить exra FD и выполнить очистку после этого, убив его, и технически это следует делать в trap '...' EXIT.
Существует лучший способ сделать это, и вы уже открыли для себя это: tee.
Только вместо того, чтобы использовать его для своего стандартного вывода, используйте тройник для стандартного вывода и один для стандартного вывода. Как ты это сделаешь? Замена процесса и перенаправление файлов:
command > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)
Давайте разделим это и объясним:
> >(..)
>(...)(процесс подстановки) создает FIFO и позволяет teeпрослушивать его. Затем он использует >(перенаправление файлов) для перенаправления STDOUT commandв FIFO, который teeпрослушивает ваш первый .
То же самое для второго:
2> >(tee -a stderr.log >&2)
Мы снова используем подстановку процессов, чтобы создать teeпроцесс, который читает из STDIN и выгружает его в stderr.log. teeвыводит свой ввод обратно на STDOUT, но так как его ввод - наш STDERR, мы хотим снова перенаправить teeSTDOUT на наш STDERR. Затем мы используем перенаправление файлов для перенаправления commandSTDERR на вход FIFO (tee STDIN).
Смотрите http://mywiki.wooledge.org/BashGuide/InputAndOutput
Замена процесса - это одна из тех приятных вещей, которые вы получаете в качестве бонуса выбора в bashкачестве оболочки (в отличие от shPOSIX или Bourne).
Во- shпервых, вам придется делать вещи вручную:
out="${TMPDIR:-/tmp}/out.$$" err="${TMPDIR:-/tmp}/err.$$"
mkfifo "$out" "$err"
trap 'rm "$out" "$err"' EXIT
tee -a stdout.log < "$out" &
tee -a stderr.log < "$err" >&2 &
command >"$out" 2>"$err"
$ echo "HANG" > >(tee stdout.log) 2> >(tee stderr.log >&2)который работает, но ждет ввода. Есть ли простая причина, почему это происходит?
/bin/bash 2> errи/bin/bash -i 2> err
(echo "Test Out";>&2 echo "Test Err") > >(tee stdout.log) 2> >(tee stderr.log >&2)
почему не просто
./aaa.sh 2>&1 | tee -a log
Это просто перенаправляет stderrна stdout, так что эхо как для входа и на экран. Может быть, я что-то упустил, потому что некоторые другие решения кажутся действительно сложными.
Примечание: начиная с bash версии 4, вы можете использовать |&как сокращение для 2>&1 |:
./aaa.sh |& tee -a log
./aaa.sh |& tee aaa.logработает (в bash).
set -o pipefailпоследующим ;или &&если я не ошибаюсь.
Это может быть полезно для людей, которые находят это через Google. Просто раскомментируйте пример, который вы хотите попробовать. Конечно, не стесняйтесь переименовывать выходные файлы.
#!/bin/bash
STATUSFILE=x.out
LOGFILE=x.log
### All output to screen
### Do nothing, this is the default
### All Output to one file, nothing to the screen
#exec > ${LOGFILE} 2>&1
### All output to one file and all output to the screen
#exec > >(tee ${LOGFILE}) 2>&1
### All output to one file, STDOUT to the screen
#exec > >(tee -a ${LOGFILE}) 2> >(tee -a ${LOGFILE} >/dev/null)
### All output to one file, STDERR to the screen
### Note you need both of these lines for this to work
#exec 3>&1
#exec > >(tee -a ${LOGFILE} >/dev/null) 2> >(tee -a ${LOGFILE} >&3)
### STDOUT to STATUSFILE, stderr to LOGFILE, nothing to the screen
#exec > ${STATUSFILE} 2>${LOGFILE}
### STDOUT to STATUSFILE, stderr to LOGFILE and all output to the screen
#exec > >(tee ${STATUSFILE}) 2> >(tee ${LOGFILE} >&2)
### STDOUT to STATUSFILE and screen, STDERR to LOGFILE
#exec > >(tee ${STATUSFILE}) 2>${LOGFILE}
### STDOUT to STATUSFILE, STDERR to LOGFILE and screen
#exec > ${STATUSFILE} 2> >(tee ${LOGFILE} >&2)
echo "This is a test"
ls -l sdgshgswogswghthb_this_file_will_not_exist_so_we_get_output_to_stderr_aronkjegralhfaff
ls -l ${0}
exec >означает, переместить цель дескриптора файла в определенное место назначения. По умолчанию установлено значение 1, поэтому exec > /dev/nullтеперь в этом сеансе вывод stdout в / dev / null перемещается. Текущие файловые дескрипторы для этого сеанса можно увидеть, выполнив ls -l /dev/fd/. Попробуй это! Затем посмотрим, что произойдет, когда вы выполните команду « exec 2>/tmp/stderr.log.Дополнительно», exec 3>&1значит, создайте новый файловый дескриптор с номером 3 и перенаправьте его на цель файлового дескриптора 1. В этом примере целью был экран, когда была выполнена команда.
Чтобы перенаправить stderr в файл, отобразите стандартный вывод на экран, а также сохраните стандартный вывод в файл:
./aaa.sh 2> ccc.out | tee ./bbb.out
РЕДАКТИРОВАТЬ : Чтобы вывести на экран и stderr, и stdout, а также сохранить их в файл, вы можете использовать перенаправление ввода / вывода bash :
#!/bin/bash
# Create a new file descriptor 4, pointed at the file
# which will receive stderr.
exec 4<>ccc.out
# Also print the contents of this file to screen.
tail -f ccc.out &
# Run the command; tee stdout as normal, and send stderr
# to our file descriptor 4.
./aaa.sh 2>&4 | tee bbb.out
# Clean up: Close file descriptor 4 and kill tail -f.
exec 4>&-
kill %1
Другими словами, вы хотите направить stdout в один фильтр ( tee bbb.out) и stderr в другой фильтр ( tee ccc.out). Не существует стандартного способа передачи чего-либо, кроме stdout, в другую команду, но вы можете обойти это, манипулируя дескрипторами файлов.
{ { ./aaa.sh | tee bbb.out; } 2>&1 1>&3 | tee ccc.out; } 3>&1 1>&2
Смотрите также Как получить стандартный поток ошибок (stderr)? и когда бы вы использовали дополнительный файловый дескриптор?
В bash (и ksh и zsh), но не в других оболочках POSIX, таких как dash, вы можете использовать подстановку процессов :
./aaa.sh > >(tee bbb.out) 2> >(tee ccc.out)
Помните, что в bash эта команда возвращается, как только ./aaa.shзавершается, даже если teeкоманды все еще выполняются (ksh и zsh ожидают подпроцессов). Это может быть проблемой, если вы делаете что-то подобное ./aaa.sh > >(tee bbb.out) 2> >(tee ccc.out); process_logs bbb.out ccc.out. В этом случае вместо этого используйте жонглирование дескриптора файла или ksh / zsh.
sh, полезный для заданий cron, где замена процесса недоступна.
Если вы используете bash:
# Redirect standard out and standard error separately
% cmd >stdout-redirect 2>stderr-redirect
# Redirect standard error and out together
% cmd >stdout-redirect 2>&1
# Merge standard error with standard out and pipe
% cmd 2>&1 |cmd2
Кредит (не отвечая из головы) идет здесь: http://www.cygwin.com/ml/cygwin/2003-06/msg00772.html
В моем случае скрипт выполнял команду, перенаправляя как stdout, так и stderr в файл, что-то вроде:
cmd > log 2>&1
Мне нужно было обновить его таким образом, чтобы в случае сбоя предпринять некоторые действия на основе сообщений об ошибках. Я мог бы, конечно, удалить dup 2>&1и захватить stderr из скрипта, но тогда сообщения об ошибках не попадут в файл журнала для справки. Хотя принятый ответ от @lhunath должен делать то же самое, он перенаправляет stdoutи stderrв разные файлы, что не то, что я хочу, но помогло мне найти точное решение, которое мне нужно:
(cmd 2> >(tee /dev/stderr)) > log
С учетом указанных выше, журнал будет иметь копию как stdoutи stderrя могу захватить stderrиз моего сценария без необходимости беспокоиться о stdout.
Следующее будет работать для KornShell (ksh), где замена процесса недоступна,
# create a combined(stdin and stdout) collector
exec 3 <> combined.log
# stream stderr instead of stdout to tee, while draining all stdout to the collector
./aaa.sh 2>&1 1>&3 | tee -a stderr.log 1>&3
# cleanup collector
exec 3>&-
Реальный трюк здесь, представляет собой последовательность из 2>&1 1>&3которых в нашем случае перенаправляет stderrк stdoutи перенаправляет stdoutк дескриптору 3. На данный момент stderrи stdoutеще не объединены.
По сути, stderr(as stdin) передается туда, teeгде он регистрируется, stderr.logа также перенаправляет на дескриптор 3.
И дескриптор 3записывает это combined.logвсе время. Таким образом, combined.logсодержит как stdoutи stderr.
Если вы используете zsh , вы можете использовать несколько перенаправлений, поэтому вам даже не нужно tee:
./cmd 1>&1 2>&2 1>out_file 2>err_file
Здесь вы просто перенаправляете каждый поток на себя и целевой файл.
Полный пример
% (echo "out"; echo "err">/dev/stderr) 1>&1 2>&2 1>/tmp/out_file 2>/tmp/err_file
out
err
% cat /tmp/out_file
out
% cat /tmp/err_file
err
Обратите внимание, что для этого требуется установить MULTIOSпараметр (который используется по умолчанию).
MULTIOSВыполнять неявные
tees илиcats при попытке нескольких перенаправлений (см. Перенаправление ).