Как мне получить STDOUT и STDERR, чтобы перейти к терминалу и файлу журнала?
У меня есть скрипт, который будет выполняться в интерактивном режиме неспециалистами. Сценарий записывает обновления состояния в STDOUT, чтобы пользователь мог быть уверен, что сценарий работает нормально.
Я хочу, чтобы STDOUT и STDERR перенаправлялись на терминал (чтобы пользователь мог видеть, что скрипт работает, а также видеть, есть ли проблема). Я также хочу, чтобы оба потока перенаправлялись в файл журнала.
Я видел кучу решений в сети. Некоторые из них не работают, а другие ужасно сложно. Я разработал работоспособное решение (которое я введу в качестве ответа), но это kludgy.
идеальным решением будет одна строка кода, которая может быть включена в начало любого скрипта, который отправляет оба потока как в терминал, так и в файл журнала.
EDIT: перенаправление STDERR в STDOUT и передача результата в tee работает, но это зависит от пользователей, которые не забывают перенаправлять и передавать вывод. Я хочу, чтобы ведение журнала быть надежным и автоматическим (именно поэтому я хотел бы иметь возможность встроить решение в сам скрипт.)
7 ответов:
используйте "тройник" для перенаправления на файл и экран. В зависимости от оболочки, которую вы используете, вы должны перенаправить stderr в stdout, используя
./a.out 2>&1 | tee output
или
./a.out |& tee output
В csh есть встроенная команда под названием "script", которая будет захватывать все, что идет на экран в файл. Вы начинаете его, набрав "script", затем делаете все, что хотите захватить, а затем нажимаете control-D, чтобы закрыть файл сценария. Я не знаю эквивалента для ш/Баш/КШ.
кроме того, поскольку теперь вы указали, что это ваши собственные скрипты sh, которые вы можете изменить, вы можете сделать перенаправление внутри, окружив весь скрипт фигурными скобками или скобками, например
#!/bin/sh { ... whatever you had in your script before } 2>&1 | tee output.file
приближается к половине десятилетия спустя...
Я считаю, что это" идеальное решение", которое ищет OP.
вот один лайнер, который вы можете добавить в верхнюю часть вашего скрипта Bash:
exec > >(tee -a $HOME/logfile) 2>&1
вот небольшой скрипт, демонстрирующий его использование:
#!/usr/bin/env bash exec > >(tee -a $HOME/logfile) 2>&1 # Test redirection of STDOUT echo test_stdout # Test redirection of STDERR ls test_stderr___this_file_does_not_exist
(Примечание: это работает только с Bash. Это будет не работа с /bin / sh.)
адаптировано из здесь; оригинал, насколько я могу судить, не поймал STDERR в лог-файле. Исправлено с примечанием от здесь.
чтобы перенаправить stderr в stdout добавьте это в вашей команде:
2>&1
Для вывода на терминал и входа в файл вы должны использоватьtee
вместе будет выглядеть так:
mycommand 2>&1 | tee mylogfile.log
EDIT: для встраивания в ваш скрипт вы бы сделали то же самое. Так что ваш скрипт
#!/bin/sh whatever1 whatever2 ... whatever3
как
#!/bin/sh ( whatever1 whatever2 ... whatever3 ) 2>&1 | tee mylogfile.log
Я создал скрипт под названием "RunScript.sh". содержание этого скрипта:
${APP_HOME}/.sh 2>&1 | tee -a ${APP_HOME}/.log
Я называю это так:
./RunScript.sh ScriptToRun Param1 Param2 Param3 ...
это работает, но для этого требуется, чтобы скрипты приложения запускались через внешний скрипт. Это немного запутано.
год спустя, вот старый скрипт bash для регистрации чего-либо. Например,
teelog make ...
регистрирует сгенерированное имя журнала (и см. трюк для регистрации вложенныхmake
s тоже.)#!/bin/bash me=teelog Version="2008-10-9 oct denis-bz" Help() { cat <<! $me anycommand args ... logs the output of "anycommand ..." as well as displaying it on the screen, by running anycommand args ... 2>&1 | tee `day`-command-args.log That is, stdout and stderr go to both the screen, and to a log file. (The Unix "tee" command is named after "T" pipe fittings, 1 in -> 2 out; see http://en.wikipedia.org/wiki/Tee_(command) ). The default log file name is made up from "command" and all the "args": $me cmd -opt dir/file logs to `day`-cmd--opt-file.log . To log to xx.log instead, either export log=xx.log or $me log=xx.log cmd ... If "logdir" is set, logs are put in that directory, which must exist. An old xx.log is moved to /tmp/$USER-xx.log . The log file has a header like # from: command args ... # run: date pwd etc. to show what was run; see "From" in this file. Called as "Log" (ln -s $me Log), Log anycommand ... logs to a file: command args ... > `day`-command-args.log and tees stderr to both the log file and the terminal -- bash only. Some commands that prompt for input from the console, such as a password, don't prompt if they "| tee"; you can only type ahead, carefully. To log all "make" s, including nested ones like cd dir1; $(MAKE) cd dir2; $(MAKE) ... export MAKE="$me make" ! # See also: output logging in screen(1). exit 1 } #------------------------------------------------------------------------------- # bzutil.sh denisbz may2008 -- day() { # 30mar, 3mar /bin/date +%e%h | tr '[A-Z]' '[a-z]' | tr -d ' ' } edate() { # 19 May 2008 15:56 echo `/bin/date "+%e %h %Y %H:%M"` } From() { # header # from: $* # run: date pwd ... case `uname` in Darwin ) mac=" mac `sw_vers -productVersion`" esac cut -c -200 <<! ${comment-#} from: $@ ${comment-#} run: `edate` in $PWD `uname -n` $mac `arch` ! # mac $PWD is pwd -L not -P real } # log name: day-args*.log, change this if you like -- logfilename() { log=`day` [[ == "sudo" ]] && shift for arg do log="$log-${arg##*/}" # basename (( ${#log} >= 100 )) && break # max len 100 done # no blanks etc in logfilename please, tr them to "-" echo $logdir/` echo "$log".log | tr -C '.:+=[:alnum:]_\n' - ` } #------------------------------------------------------------------------------- case "" in -v* | --v* ) echo " version: $Version" exit 1 ;; "" | -* ) Help esac # scan log= etc -- while [[ == [a-zA-Z_]*=* ]]; do export "" shift done : ${logdir=.} [[ -w $logdir ]] || { echo >&2 "error: $me: can't write in logdir $logdir" exit 1 } : ${log=` logfilename "$@" `} [[ -f $log ]] && /bin/mv "$log" "/tmp/$USER-${log##*/}" case ${0##*/} in # basename log | Log ) # both to log, stderr to caller's stderr too -- { From "$@" "$@" } > $log 2> >(tee /dev/stderr) # bash only # see http://wooledge.org:8000/BashFAQ 47, stderr to a pipe ;; * ) #------------------------------------------------------------------------------- { From "$@" # header: from ... date pwd etc. "$@" 2>&1 # run the cmd with stderr and stdout both to the log } | tee $log # mac tee buffers stdout ? esac
использовать
script
команда в вашем скрипте (man 1 script)создайте оболочку shellscript (2 строки), которая настраивает script (), а затем вызывает exit.
Часть 1: wrap.sh
#!/bin/sh script -c './realscript.sh' exit
Часть 2: realscript.sh
#!/bin/sh echo 'Output'
результат:
~: sh wrap.sh Script started, file is typescript Output Script done, file is typescript ~: cat typescript Script started on fr. 12. des. 2008 kl. 18.07 +0100 Output Script done on fr. 12. des. 2008 kl. 18.07 +0100 ~: