which
на самом деле плохой способ сделать вещи как это, поскольку он высказывает предположения о Вашей среде на основе $SHELL
и файлы запуска (это думает), та оболочка использование; мало того, что это иногда не угадывает, но и Вы не можете обычно говорить этому вести себя по-другому. (which
на моей Ubuntu 10.10 не понимает --skip-alias
как упомянуто @SiegeX, например.) type
использует текущую среду оболочки вместо того, чтобы ввести по абсолютному адресу в Ваших файлах конфигурации и может быть сказан проигнорировать части той среды, таким образом, она показывает Вам, что на самом деле произойдет вместо того, что произошло бы в реконструкции Вашей оболочки по умолчанию.
В этом случае, type -P
обойдет любые псевдонимы или функции:
$ type -P vim
/usr/bin/vim
Можно также попросить, чтобы это сняло со всех слоев, по одному, и показало Вам, что это нашло бы:
$ type -a vim
vim is aliased to `vim -X'
vim is /usr/bin/vim
(Подробно останавливающийся на этом из комментариев:)
Проблема с which
это, это обычно - внешняя программа вместо встроенной оболочки, что означает, что это не видит Ваши псевдонимы или функции и должно попытаться восстановить их от запуска/файлов конфигурации оболочки. (Если это - встроенная оболочка, как это находится в zsh
но по-видимому нет bash
, это, более вероятно, будет использовать среду оболочки и делать правильную вещь.)
type
совместимая POSIX команда, которая требуется, чтобы вести себя, как будто это было встроенное (то есть, это должно использовать среду оболочки, это вызывается от включения локальных псевдонимов и функций), таким образом, это обычно - встроенное.
Это обычно не находится в csh
/tcsh
, хотя в большинстве современных версий тех which
встроенная оболочка и делает правильную вещь; иногда встроенное what
вместо этого, и иногда нет никакого хорошего способа видеть среду текущей оболочки от csh
/tcsh
вообще.
Когда Вы используете конструкцию: 1>stdout.log 2>&1
и stderr и stdout перенаправляются в файл, потому что stdout перенаправление настраивается перед stderr перенаправлением.
При инвертировании порядка, можно получить stdout, перенаправленный в файл, и затем скопировать stderr в stdout, таким образом, можно передать его по каналу к tee
.
$ cat test
#!/bin/sh
echo OUT! >&1
echo ERR! >&2
$ ./test 2>&1 1>stdout.log | tee stderr.log
ERR!
$ cat stdout.log
OUT!
$ cat stderr.log
ERR!
Даже без любого перенаправления, или с только >logfile 2>&1
, Вы, как гарантируют, не будете видеть вывода в порядке поколения.
Для начала, stdout из приложения будет с буфером строки (к tty) или буферизованный (к конвейеру), но stderr освобожден буфер, таким образом, отношения между порядком вывода повреждаются, что касается читателя. Последующие этапы в любом конвейере, который Вы могли придумать, не получат детерминировано заказанный доступ к этим двум потокам (они - концептуально вещи, происходящие параллельно, и Вы всегда подвергаетесь планировщику - если к тому времени, когда Ваш читатель получает часть, писатель уже записал в оба канала, Вы не можете сказать, который был на первом месте).
"[T] он приказывает, чтобы они произошли", только действительно известен приложению. Упорядочивание вывода через stdout/stderr является известным - классиком, возможно - проблема.
Позволить f
будьте командой, которую Вы хотели бы быть выполненными, затем это
( exec 3>/tmp/log; f 2>&1 1>&3 |tee >(cat)>&3 )
должен дать Вам, чего Вы желаете. Например, wget -O - www.google.de
был бы похож на это:
( exec 3>/tmp/googlelog; wget -O - www.google.de 2>&1 1>&3 |tee >(cat)>&3 )
Вы хотите копировать поток сообщений об ошибках так, чтобы это появилось и на консоли и в файле журнала. Инструмент для этого tee
, и все, что необходимо сделать, применяют его к потоку сообщений об ошибках. К сожалению, нет никакой стандартной конструкции оболочки для передачи по каналу потока сообщений об ошибках команды в другую команду, таким образом, немного перестановки дескриптора файла требуется.
{ { echo out; echo err 1>&2; } 2>&1 >&3 | tee /dev/tty; } >log 3>&1
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^
command produces output stdout→3 →log
command produces error stderr→1 dup to terminal →log
tee
представляет задержку здесь также. Я не думаю, что существует чистое решение для оболочки. На самом деле интересно, существует ли решение, не изменяя приложение в некотором роде.
– Gilles 'SO- stop being evil'
19.03.2011, 23:28
Я смог выполнить это путем размещения следующей строки наверху сценария удара:
exec 1>>log 2> >(tee -a log >&2)
Это перенаправит stdout в файл log
(1>>log
), затем кладите stderr для первого удара в файл log
(2> >(tee -a log
) и направьте его назад к stderr (>&2)
. Таким образом я получаю единственный файл, log
, который показывает и stdout и stderr в порядке, и stderr также отображен на экране, как обычно.
Выгода - то, что это только, кажется, работает, когда я добавляю в файл. Если я не добавляю, кажется, что эти два перенаправления ударяют друг друга, и я только добираюсь, какой бы ни выводы длятся.
Чтобы записать stderr на экран и записать ОБЕ stderr и stdout в файл - И чтобы строки для stderr и stdout выходили в той же последовательности, что и если бы оба были записаны на экран:
Оказывается, сложная проблема, особенно часть, касающаяся «одинаковой последовательности», которую можно было бы ожидать, если бы вы просто записали их на экран. Проще говоря: запишите каждую в отдельный файл, сделайте некоторую магию фонового процесса, чтобы пометить каждую строку (в каждом файле) с точным временем создания строки, а затем: "tail --follow" файл stderr на экран , но чтобы увидеть ОБЕ "stderr" и "stdout" вместе - по порядку - отсортируйте два файла (с метками точного времени на каждой строке) вместе.
Код:
# Set the location of output and the "first name" of the log file(s)
pth=$HOME
ffn=my_log_filename_with_no_extension
date >>$pth/$ffn.out
date >>$pth/$ffn.err
# Start background processes to handle 2 files, by rewriting each one line-by-line as each line is added, putting a label at front of line
tail -f $pth/$ffn.out | perl -nle 'use Time::HiRes qw(time);print substr(time."0000",0,16)."|1|".$_' >>$pth/$ffn.out.txt &
tail -f $pth/$ffn.err | perl -nle 'use Time::HiRes qw(time);print substr(time."0000",0,16)."|2|".$_' >>$pth/$ffn.err.txt &
sleep 1
# Remember the process id of each of 2 background processes
export idout=`ps -ef | grep "tail -f $pth/$ffn.out" | grep -v 'grep' | perl -pe 's/\s+/\t/g' | cut -f2`
export iderr=`ps -ef | grep "tail -f $pth/$ffn.err" | grep -v 'grep' | perl -pe 's/\s+/\t/g' | cut -f2`
# Run the command, sending stdout to one file, and stderr to a 2nd file
bash mycommand.sh 1>>$pth/$ffn.out 2>>$pth/$ffn.err
# Remember the exit code of the command
myexit=$?
# Kill the two background processes
ps -ef | perl -lne 'print if m/^\S+\s+$ENV{"idout"}/'
echo kill $idout
kill $idout
ps -ef | perl -lne 'print if m/^\S+\s+$ENV{"iderr"}/'
echo kill $iderr
kill $iderr
date
echo "Exit code: $myexit for '$listname', list item# '$ix', bookcode '$bookcode'"
Да, это кажется сложным, и в результате получается 4 выходных файла (2 из которых вы можете удалить).Похоже, что это сложная проблема, поэтому потребовалось несколько механизмов.
В конце, чтобы увидеть результаты ОБЕИХ stdout и stderr в ожидаемой последовательности, выполните следующее:
cat $pth/$ffn.out.txt $pth/$ffn.err.txt | sort
Единственная причина, по которой последовательность, по крайней мере, очень близка к той, которая была бы, если бы и stdout, и stderr Просто перешел на экран: Каждая строка помечена меткой времени с точностью до миллисекунды.
Чтобы увидеть stderr на экране по мере продвижения процесса, используйте это:
tail -f $pth/$ffn.out
Надежда, которая поможет кому-то, кто прибыл сюда спустя много времени после того, как был задан исходный вопрос.
Учитывая то, что я здесь прочитал, единственное решение, которое я вижу, - это добавить к каждой строке, STOUT или STERR, временной интервал / метку времени. date +% s дойдет до секунд, но это слишком медленно для поддержания порядка. Кроме того, журнал нужно как-то отсортировать. Больше работы, чем я способен.
He tenido problemas con este requisito exacto y, al final, no pude encontrar una solución simple. Lo que terminé haciendo en su lugar fue esto:
TMPFILE=/tmp/$$.log
myCommand > $TMPFILE 2>&1
[ $? != 0 ] && cat $TMPFILE
date >> myCommand.log
cat $TMPFILE >> myCommand.log
rm -f $TMPFILE
Agrega stdout y stderr, en el orden intercalado adecuado, al archivo de registro. Y si ocurriera algún error (según lo determinado por el estado de salida del comando ), envía la salida completa (stdout y stderr )a stdout, nuevamente en el orden intercalado correcto. Encontré que esto es un compromiso razonable para mis necesidades. Si desea un único archivo de registro de ejecución -en lugar de uno de ejecución múltiple -creciente, es aún más simple:
myCommand > myCommand.log 2>&1
[ $? != 0 ] && cat myCommand.log
stderr para comando -sustituido tee -a
, y stdout agregado al mismo archivo:
./script.sh 2> >(tee -a outputfile) >>outputfile
y nota :también aseguran el orden correcto (pero sin stderr -show )hay un comando 'unbuffer' de las herramientas 'expect', que simula tty y mantiene stdout/err en orden como lo haría mostrar en terminal:
unbuffer./script.sh > outputfile
tee -a
с тем же файлом, используемым в1>
суммировать оба вывода в том же файле. Что-то как:./test 2>&1 1>out+err.log | tee -a out+err.log
– mmoya 19.03.2011, 19:41wget -O - www.google.de
для меня. (сравните с решением ниже), – artistoex 19.03.2011, 19:56tee -a
не будет работать надежно, чтобы иметь тот же вывод, который был бы на консоли, если бы ничто не было перенаправлено. Вывод, который идет черезtee
мог бы быть немного отложен по сравнению с выводом, который прибывает непосредственно из команды и так мог бы появиться позже в журнале. – Gilles 'SO- stop being evil' 19.03.2011, 22:33