Покажите только stderr на экране, но запишите и stdout и stderr в файл

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 вообще.

24
21.05.2011, 05:14
9 ответов

Когда Вы используете конструкцию: 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!
7
27.01.2020, 19:41
  • 1
    Это не позволяет Вам зарегистрировать эти два потока в тот же файл. –  artistoex 19.03.2011, 18:19
  • 2
    @artistoex: просто можно использовать tee -a с тем же файлом, используемым в 1> суммировать оба вывода в том же файле. Что-то как: ./test 2>&1 1>out+err.log | tee -a out+err.log –  mmoya 19.03.2011, 19:41
  • 3
    я понятия не имею, почему, но это не работает с wget -O - www.google.de для меня. (сравните с решением ниже), –  artistoex 19.03.2011, 19:56
  • 4
    Используя tee -a не будет работать надежно, чтобы иметь тот же вывод, который был бы на консоли, если бы ничто не было перенаправлено. Вывод, который идет через tee мог бы быть немного отложен по сравнению с выводом, который прибывает непосредственно из команды и так мог бы появиться позже в журнале. –  Gilles 'SO- stop being evil' 19.03.2011, 22:33
  • 5
    Это не работает на меня, out+err.log пуст. И да, я хочу stderror и стандарт в том же файле –  Andreas 19.03.2011, 22:41

Даже без любого перенаправления, или с только >logfile 2>&1, Вы, как гарантируют, не будете видеть вывода в порядке поколения.

Для начала, stdout из приложения будет с буфером строки (к tty) или буферизованный (к конвейеру), но stderr освобожден буфер, таким образом, отношения между порядком вывода повреждаются, что касается читателя. Последующие этапы в любом конвейере, который Вы могли придумать, не получат детерминировано заказанный доступ к этим двум потокам (они - концептуально вещи, происходящие параллельно, и Вы всегда подвергаетесь планировщику - если к тому времени, когда Ваш читатель получает часть, писатель уже записал в оба канала, Вы не можете сказать, который был на первом месте).

"[T] он приказывает, чтобы они произошли", только действительно известен приложению. Упорядочивание вывода через stdout/stderr является известным - классиком, возможно - проблема.

14
27.01.2020, 19:41

Позволить 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 )
0
27.01.2020, 19:41
  • 1
    , Это почти работает на меня, но в файле журнала я сначала получаю все stdout строки и затем все stderror строки. Я хочу, чтобы они были чередованы в естественном порядке, как они происходят. –  Andreas 19.03.2011, 22:44

Вы хотите копировать поток сообщений об ошибках так, чтобы это появилось и на консоли и в файле журнала. Инструмент для этого 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
1
27.01.2020, 19:41
  • 1
    Это также, действительно не совсем работает на меня, я получаю stdout строки сначала и затем все stderr строки в файле 'журнала'. пример: {{ эхо; эхо допускает ошибку 1> &2; эхо out2; err2 1 эха> &2;} 2> &1> &3 | кладут/dev/tty для первого удара;}> регистрируют 3> &1 –  Andreas 19.03.2011, 22:56
  • 2
    @Andreas: О, понятное дело, 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 также отображен на экране, как обычно.

Выгода - то, что это только, кажется, работает, когда я добавляю в файл. Если я не добавляю, кажется, что эти два перенаправления ударяют друг друга, и я только добираюсь, какой бы ни выводы длятся.

7
27.01.2020, 19:41

Чтобы записать 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

Надежда, которая поможет кому-то, кто прибыл сюда спустя много времени после того, как был задан исходный вопрос.

1
27.01.2020, 19:41

Учитывая то, что я здесь прочитал, единственное решение, которое я вижу, - это добавить к каждой строке, STOUT или STERR, временной интервал / метку времени. date +% s дойдет до секунд, но это слишком медленно для поддержания порядка. Кроме того, журнал нужно как-то отсортировать. Больше работы, чем я способен.

0
27.01.2020, 19:41

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
2
27.01.2020, 19:41

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
1
27.01.2020, 19:41

Теги

Похожие вопросы