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

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

exec 2>> ${errorLog}

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

Ответ 1

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

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

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

exec 2> >(foo)

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

Ответ 2

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

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

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

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

Ответ 3

В этом примере перенаправляются 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 можно полагаться на это в настоящее время.

Ответ 5

cat q23123  2> tmp_file ;cat tmp_file | sed -e "s/^/$(date '+[%F %T]'): /g" >> output.log; rm -f tmp_file