Предварительно ожидая метка времени к каждой строке вывода от команды

Из Вашего описания это кажется, что Ваше определенное обстоятельство могло быть решено путем создания задания крона, которое также уничтожило/перезапустило процесс хвоста. Но в целом, (Mac OS, являющийся исключением), хвост будет помнить, где Вы находитесь в файле (то есть, байтовое смещение). Кроме того, открытый дескриптор файла указывает на конечный файл, не символьную ссылку. Символьная ссылка становится не важной процессу считывания, после того как файл был открыт. Хотя возможно иметь функции, которые вновь открыли файл на основе первоначального тракта, когда что-то изменяется, большинство реализаций не делает этого.

199
11.12.2012, 17:08
8 ответов

moreutils включает ts который делает это вполне приятно:

command | ts '[%Y-%m-%d %H:%M:%S]'

Это избавляет от необходимости цикл также, каждой строке вывода поставят метку времени это.

$ echo -e "foo\nbar\nbaz" | ts '[%Y-%m-%d %H:%M:%S]'
[2011-12-13 22:07:03] foo
[2011-12-13 22:07:03] bar
[2011-12-13 22:07:03] baz

Вы хотите знать, когда тот сервер возвратился, Вы перезапустили? Просто выполненный ping | ts , проблема решена :D.

294
27.01.2020, 19:27
  • 1
    Как я не знал об этом?!?!?! Этот хвост дополнений-f удивительно! tail -f /tmp/script.results.txt | ts –  Bruno Bronosky 06.03.2015, 00:51
  • 2
    , если у меня нет команды ts, что я должен использовать? –  ekassis 16.01.2017, 13:48
  • 3
    , Если это не работает, пытается перенаправить stderr к stdout, например. ssh -v 127.0.0.1 2>&1 | ts –  jchook 20.03.2017, 21:02

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

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

Оболочка POSIX

Примите во внимание, что, так как много оболочек хранят свои строки внутренне как cstrings, если вход содержит нулевой символ (\0), это может заставить строку заканчиваться преждевременно.

command | while IFS= read -r line; do printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$line"; done

GNU awk

command | gawk '{ print strftime("[%Y-%m-%d %H:%M:%S]"), $0 }'

Perl

command | perl -pe 'use POSIX strftime; print strftime "[%Y-%m-%d %H:%M:%S] ", localtime'

Python

command | python -c 'import sys,time;sys.stdout.write("".join(( " ".join((time.strftime("[%Y-%m-%d %H:%M:%S]", time.localtime()), line)) for line in sys.stdin )))'

Ruby

command | ruby -pe 'print Time.now.strftime("[%Y-%m-%d %H:%M:%S] ")'
108
27.01.2020, 19:27
  • 1
    Одна проблема здесь состоит в том, что много программ включают еще более выходную буферизацию, когда их stdout является каналом вместо терминала. –  cjm 13.12.2011, 20:02
  • 2
    @cjm - Верный. Некоторая выходная буферизация может быть облегчена при помощи stdbuf -o 0, но если программа вручную обработает свою выходную буферизацию, то она не поможет (если не будет опция отключить/уменьшить размер буфера вывода). –  Chris Down 14.12.2011, 00:46
  • 3
    Для Python можно отключить буферизацию строки с python -u –  ibizaman 22.11.2016, 00:01
  • 4
    @Bwmat Нет. ... for x in sys.stdin выполняет итерации по строкам, не буферизуя их всех в память сначала. –  Chris Down 26.12.2016, 14:36
  • 5
    Делает это, и Вы получаете буферизацию... для в 1 1 1 1 1; действительно спите 1; эхо; сделанный | Python-c 'импортируют sys, время; sys.stdout.write ("" .join (("".join ((time.strftime (" [%Y-% m-% d %H: % M: % S]", time.gmtime ()), строка)) для строки в sys.stdin)))' –  ChuckCottrill 04.01.2018, 02:06

Это можно сделать с помощью date и xargs :

... | xargs -L 1 echo `date +'[%Y-%m-%d %H:%M:%S]'` $1

Объяснение:

xargs -L 1 сообщает xargs для запуска следующей команды для каждой 1 строки ввода, и при этом она передает первую строку. echo `date + '[% Y-% m-% d% H:% M:% S]'` $ 1 в основном отображает дату с входным аргументом в конце

{{ 1}}
1
27.01.2020, 19:27

Для построчного измерения дельты попробуйте gnomon .

Это утилита командной строки, немного похожая на ts из moreutils, которая добавляет информацию о временной метке к стандартному выводу другой команды. Полезно для длительно выполняющихся процессов, когда вы хотите иметь исторические записи о том, что занимает так много времени.

При передаче чего-либо в gnomon к каждой строке добавляется временная метка, указывающая, как долго эта строка была последней строкой в ​​буфере, то есть сколько времени потребовалось для появления следующей строки. По умолчанию gnomon будет отображать секунды, прошедшие между каждой строкой, но это можно настроить.

gnomon demo

44
27.01.2020, 19:27

Сообщение Райана действительно дает интересную идею, однако это терпит неудачу в нескольких отношениях.При тестировании с tail -f / var / log / syslog | xargs -L 1 echo $ (date + '[% Y-% m-% d% H:% M:% S]') $ 1 , я заметил, что метка времени остается прежней, даже если stdout приходит позже с разницей в секундах. Рассмотрим следующий результат:

[2016-07-14 01:44:25] Jul 14 01:44:32 eagle dhclient[16091]: DHCPREQUEST of 192.168.0.78 on wlan7 to 255.255.255.255 port 67 (xid=0x411b8c21)
[2016-07-14 01:44:25] Jul 14 01:44:34 eagle avahi-daemon[740]: Joining mDNS multicast group on interface wlan7.IPv6 with address fe80::d253:49ff:fe3d:53fd.
[2016-07-14 01:44:25] Jul 14 01:44:34 eagle avahi-daemon[740]: New relevant interface wlan7.IPv6 for mDNS.

Предлагаемое мной решение аналогично, однако обеспечивает правильную отметку времени и использует несколько более переносимый printf , а не echo

| xargs -L 1 bash  -c 'printf "[%s] %s\n" "$(date +%Y-%m-%d\ %H:%M:%S )" "$*" ' bash

Почему bash -c '.. . 'bash ? Поскольку из-за опции -c первый аргумент присваивается $ 0 и не отображается в выводе. Обратитесь к странице руководства вашей оболочки для правильного описания -c

. Тестирование этого решения с помощью tail -f / var / log / syslog и (как вы, вероятно, догадались) отключение и повторное подключение к моей Wi-Fi, показал правильную метку времени, обеспечиваемую сообщениями date и syslog .

Bash может быть заменен любой оболочкой, подобной bourne, может быть выполнен с помощью любого ksh или тире , по крайней мере те, у которых есть опция -c .

Возможные проблемы:

Решение требует наличия xargs , который доступен в POSIX-совместимых системах, поэтому необходимо охватить большинство Unix-подобных систем. Очевидно, не будет работать, если ваша система не совместима с POSIX или не имеет GNU findutils

7
27.01.2020, 19:27

В большинстве ответов предлагается использовать дату , но это достаточно медленно. Если ваша версия bash выше 4.2.0, лучше использовать printf , это встроенная функция bash. Если вам нужно поддерживать устаревшие версии bash, вы можете создать журнал ] зависит от версии bash:

TIMESTAMP_FORMAT='%Y-%m-%dT%H:%M:%S'
# Bash version in numbers like 4003046, where 4 is major version, 003 is minor, 046 is subminor.
printf -v BV '%d%03d%03d' ${BASH_VERSINFO[0]} ${BASH_VERSINFO[1]} ${BASH_VERSINFO[2]}
if ((BV > 4002000)); then
log() {
    ## Fast (builtin) but sec is min sample for most implementations
    printf "%(${TIMESTAMP_FORMAT})T %5d %s\n" '-1' $$ "$*"  # %b convert escapes, %s print as is
}
else
log() {
    ## Slow (subshell, date) but support nanoseconds and legacy bash versions
    echo "$(date +"${TIMESTAMP_FORMAT}") $$ $*"
}
fi

См. разницу в скорости:

user@host:~$time for i in {1..10000}; do printf "%(${TIMESTAMP_FORMAT})T %s\n" '-1' "Some text" >/dev/null; done

real    0m0.410s
user    0m0.272s
sys     0m0.096s
user@host:~$time for i in {1..10000}; do echo "$(date +"${TIMESTAMP_FORMAT}") Some text" >/dev/null; done

real    0m27.377s
user    0m1.404s
sys     0m5.432s

UPD: вместо $ (date + "$ {TIMESTAMP_FORMAT}") лучше использовать $ (exec date + "$ {TIMESTAMP_FORMAT}") или даже $ (exec -c date + "$ {TIMESTAMP_FORMAT}") слишком ускоряют выполнение.

3
27.01.2020, 19:27

Бессовестная заглушка для чего-то, что я только что написал для решения именно этой проблемы :ets, написанного на Go.

demo

Вы можете найти множество примеров использования на странице проекта.

Заметное отличие от существующих ответов и аналогичных предложений заключается в том, что etsпредназначен для запуска вашей команды для вас в pty (псевдотерминале )— то есть имитация вашей команды, работающей изначально в телетайп. По сравнению с выводом команды по конвейеру, например. ts, это делает отметку времени более прозрачной и решает множество проблем конвейерной передачи:

  • Некоторые программы агрессивно буферизуются при записи в канал, так что вы не видите вывода, а затем получаете целую кучу вывода (да, вы можете использовать stdbuf для них, вы даже можете обернуть stdbuf и ts в псевдоним/функцию, но не лучше ли, если все будет работать из коробки );
  • Некоторые программы отключают цвет и/или интерактивность при записи в канал;
  • Статус выхода отсутствует, если вы не включили pipefail; и т. д.

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

etsподдерживает те же режимы отметки времени, что и moreutils ts:: режим абсолютного времени, режим прошедшего времени и режим инкрементного времени. Он использует более разумные значения по умолчанию (, например. монотонные часы всегда используются для отметок прошедшего/инкрементного времени )и имеют дополнительную поддержку пользовательских часовых поясов. Подробное сравнение здесь .

Еще раз,https://github.com/zmwangx/ets. Пробуйте, сообщайте об ошибках и т. д.

5
16.06.2020, 16:50

Если вы работаете в bash, поместите это в начало скрипта

exec &> >( ts '%Y-%m-%d.%H%M.%.S ' )  # prepend a timestamp to all output

Или, для дополнительной оценки, вывод в лог-файл через:

script_name=foobar
log_file=$( printf "/tmp/${script_name}-%(%Y-%m-%d)T.%(%H%M%S)T.log" -1 )
echo "note: redirecting output to [${log_file}]"
exec &> >( ts '%Y-%m-%d %H:%M:%.S ' > ${log_file} )

для вывода на консоль и в файл журнала:

script_name=foobar
log_file=$( printf "/tmp/${script_name}-%(%Y-%m-%d)T.%(%H%M%S)T.log" -1 )
exec &> >( ts '%Y-%m-%d %H:%M:%.S ' | tee ${log_file} )

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

Программа tsнаходится в пакете moreutils, который должен быть легко доступен при любом разумном режиме администрирования.:-)

1
04.12.2020, 14:41

Теги

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