Добавить текст к перенаправлениям stderr в bash

Прямо сейчас я использую exec для перенаправления stderr в журнал ошибок с помощью

exec 2>> ${errorLog}

Единственным недостатком является то, что я должен начинать каждый запуск с временной метки, так как exec просто помещает текст прямо в файл журнала. Есть ли способ перенаправить stderr, но разрешить мне добавлять к нему текст, например отметку времени?


person dragonmantank    schedule 07.01.2009    source источник


Ответы (3)


Это очень интересно. Я спросил парня, который довольно хорошо знает bash, и он сказал мне так:

 foo() { while IFS='' read -r line; do echo "$(date) $line" >> file.txt; done; };

Во-первых, это создает функцию, считывающую одну строку необработанного ввода со стандартного ввода, в то время как присваивание IFS заставляет ее не игнорировать пробелы. Прочитав одну строку, он выводит ее с добавлением соответствующих данных. Затем вы должны указать bash перенаправить stderr в эту функцию:

exec 2> >(foo)

Все, что вы пишете в stderr, теперь будет проходить через функцию foo. Обратите внимание, когда вы делаете это в интерактивной оболочке, вы больше не увидите приглашение, потому что оно печатается в stderr, а чтение в foo буферизуется строкой :)

person Johannes Schaub - litb    schedule 07.01.2009
comment
$ foo() { while IFS='' читать строку -r; сделать echo $(date) $line ›› file.txt; сделано; }; $ exec 2› ›(foo) Предупреждение: Произошел сбой программы '/bin/bash'. упс - person Peter; 19.04.2012
comment
Но если я изменю это на: echo 2 | tee ›(foo), то работает нормально. - person Peter; 19.04.2012
comment
В вопросе каждая строка добавляется к уже открытому файлу. В ответ файл журнала открывается для каждой строки. И поиск в конец файла тоже необходим. Возможно, будет лучше сделать второй exec в foo. - person ceving; 28.10.2014

Вы можете просто использовать:

exec 1> >( sed "s/^/$(date '+[%F %T]'): /" | tee -a ${LOGFILE}) 2>&1

Это не полностью решит вашу проблему, связанную с тем, что подсказка не отображается (она будет отображаться через короткое время, но не в реальном времени, поскольку канал будет кэшировать некоторые данные...), но будет отображать вывод 1: 1 на стандартный вывод, а также в файл.

Единственная проблема в том, что я не мог решить, это сделать это из функции, так как это открывает подоболочку, где exec бесполезен для основной программы...

person Matya    schedule 08.08.2011
comment
При этом все строки получают одинаковую отметку времени? - person ceving; 28.10.2014

В этом примере выполняется перенаправление stdout и stderr без потери исходных stdout и stderr. Также ошибки в обработчике stdout регистрируются в обработчике stderr. Дескрипторы файлов сохраняются в переменных и закрываются в дочерних процессах. Bash заботится о том, чтобы не возникало столкновений.

#! /bin/bash

stamp ()
{
  local LINE
  while IFS='' read -r LINE; do
    echo "$(date '+%Y-%m-%d %H:%M:%S,%N %z') $$ $LINE"
  done
}

exec {STDOUT}>&1
exec {STDERR}>&2
exec 2> >(exec {STDOUT}>&-; exec {STDERR}>&-; exec &>> stderr.log; stamp)
exec > >(exec {STDOUT}>&-; exec {STDERR}>&-; exec >> stdout.log; stamp)

for n in $(seq 3); do
  echo loop $n >&$STDOUT
  echo o$n
  echo e$n >&2
done

Для этого требуется текущая версия Bash, но благодаря Shellshock теперь на это можно положиться.

person ceving    schedule 28.10.2014