Как получить заказанный STDOUT/STDERR и добавить метку времени/префиксы?

Необходимо использовать выражение оценки

#!/bin/bash

VER_URXVT='urxvt -help 2>&1 | head -n 2'
echo $VER_URXVT
eval $VER_URXVT

От оценки страницы справочника

          The  args  are read and concatenated together into a single com-
          mand.  This command is then read and executed by the shell,  and
          its  exit status is returned as the value of eval.  If there are
          no args, or only null arguments, eval returns 0.
27
27.12.2019, 17:14
3 ответа

Метод #1. Использование файловых дескрипторов и awk

А как насчет чего-то подобного, используя решения из этого SO Q&A под заголовком: Есть ли утилита Unix для подготовки временных меток к строкам текста? и этот SO Q&A под заголовком: труба STDOUT и STDERR к двум разным процессам в сценарии командной строки?.

Подход

Шаг 1, мы создаем 2 функции в Bash, которые при вызове:

$ msgOut () {  awk '{ print strftime("STDOUT: %Y-%m-%d %H:%M:%S"), $0; fflush(); }'; }
$ msgErr () {  awk '{ print strftime("STDERR: %Y-%m-%d %H:%M:%S"), $0; fflush(); }'; }

Шаг 2 вы бы использовали вышеперечисленные функции так, чтобы получить нужное сообщение:

$ { { { ...command/script... } 2>&3; } 2>&3 | msgErr; } 3>&1 1>&2 | msgOut

Пример

Здесь я придумал пример, который будет записывать a в STDOUT, спит 10 секунд, а затем записывает вывод в STDERR. Когда мы помещаем эту последовательность команд в нашу вышеприведенную конструкцию, мы получаем сообщения, как вы указали.

$ { { echo a; sleep 10; echo >&2 b; } 2>&3 | \
    msgErr; } 3>&1 1>&2 | msgOut
STDERR: 2014-09-26 09:22:12 a
STDOUT: 2014-09-26 09:22:22 b

Метод #2. Используя annotate-output

Есть инструмент под названием annotate-output, который является частью пакета devscripts, который будет делать то, что вы хотите. Единственным ограничением является то, что он должен запускать скрипты за вас.

Пример

Если мы поместим вышеприведенную последовательность команд в скрипт под названием mycmds.bash так:

$ cat mycmds.bash 
#!/bin/bash

echo a
sleep 10
echo >&2 b

Затем мы можем запустить его так:

$ annotate-output ./mycmds.bash 
09:48:00 I: Started ./mycmds.bash
09:48:00 O: a
09:48:10 E: b
09:48:10 I: Finished with exitcode 0

Формат вывода может управляться для части, содержащей метку времени, но не более того. Но он похож на то, что вы ищете, так что он может соответствовать счету.

7
27.01.2020, 19:39

Я подозреваю, что часть вашей проблемы связана с тем, как вы построили свой heredoc. Попробуйте это так:

$ ftp -n ${FTP_HOST} << STOP
user ${FTP_USERNAME} ${FTP_PASSWORD}

binary
lcd ${FTP_FROM_DIR}
cd ${FTP_TO_DIR}
put ${reportFileName}   
STOP

Если вы действительно хотите, чтобы эти пробелы/вкладки в команде, то вам нужно будет перейти к этой форме heredoc:

$ ftp -n ${FTP_HOST} <<-STOP
    user ${FTP_USERNAME} ${FTP_PASSWORD}

    binary
    lcd ${FTP_FROM_DIR}
    cd ${FTP_TO_DIR}
    put ${reportFileName}   
STOP

Всякий раз, когда у вас есть пробелы/вкладки в heredoc вы должны использовать < < - , чтобы сказать оболочке, чтобы удалить ведущие пробелы/вкладки перед выполнением команд, которые содержатся в.

Боковая панель по использованию эхо

Когда вы анализируете переменные в сценариях и невинно используете эхо для печати сообщений, вы обычно получаете больше, чем просто последовательность, который вам интересен. echo также включает символ конечной новой строки. Его можно увидеть в следующем примере:

$ echo $(echo hi) | hexdump -C
00000000  68 69 0a                                          |hi.|
00000003

Код 0a является кодом ASCII для новой строки. Это поведение обычно нужно отключить с помощью переключателя -n на echo :

$ echo -n $(echo hi) | hexdump -C
00000000  68 69                                             |hi|
00000002

или даже лучше, модернизация с помощью printf .

Ссылки

-121-196463-

Можно использовать perl :

$ perl -e 'print pack "I>", shift' $(( RANDOM << 17 | RANDOM << 2 | RANDOM >> 13 ))
-121--84652-

. Простая оболочка, которая подает оба выхода данной команды в два экземпляра sed (один для stderr , другой для stdout ), которые выполняют маркирование.

#!/bin/bash
exec 3>&1
coproc SEDo ( sed "s/^/STDOUT: /" >&3 )
exec 4>&2-
coproc SEDe ( sed "s/^/STDERR: /" >&4 )
eval $@ 2>&${SEDe[1]} 1>&${SEDo[1]}
eval exec "${SEDo[1]}>&-"
eval exec "${SEDe[1]}>&-"

Обратите внимание на несколько вещей:

  1. Это волшебное воплощение для многих людей (включая меня) - не просто так (см. связанный ответ ниже).

  2. Нет никакой гарантии, что он не будет иногда менять пару строк - все зависит от планирования сопроцессов. Собственно, почти гарантировано, что в какой-то момент времени так и будет. При строгом сохранении порядка необходимо обработать данные из stderr и stdin в одном и том же процессе, в противном случае планировщик ядра может (и будет) создать из этого беспорядок.

    Если я правильно понимаю проблему, это означает, что вам нужно поручить оболочке перенаправить оба потока на один процесс (что можно сделать AFAIK). Проблема начинается, когда этот процесс начинает решать, что действовать в первую очередь - он должен будет опросить оба источника данных и в какой-то момент перейти в состояние, когда он будет обрабатывать один поток и данные будут поступать в оба потока до его завершения. И именно там он и разрушается. Это также означает, что свертывание выходных syscalls, таких как stderred , вероятно, является единственным способом достижения желаемого результата (и даже тогда у вас может возникнуть проблема, когда что-то станет многопоточным в многопроцессорной системе).

Что касается сопроцессов, обязательно прочитайте превосходный ответ Стефана в Как вы используете команду coroc в Bash? для глубокого понимания.

14
27.01.2020, 19:39

Ввиду того, что ваши сценарии, по сути, разбивают свой вывод на два отдельных канала, становится физически невозможным, чтобы даже одна программа, подключенная к этим каналам, на 100 % гарантировала отсутствие перестановки строк -, ей пришлось бы выполнять чередующиеся не -блокирует чтение из этих каналов, и в какой-то момент ему придется решать, из какого канала читать дальше. Тем не менее, я подозреваю, что даже эмуляторам терминала нельзя доверять в идеальном сохранении порядка строк.

0
06.08.2020, 17:03

Теги

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