Я хочу добавить метку времени к каждой строке вывода команды. Например:
foo
bar
baz
станет
[2011-12-13 12:20:38] foo
[2011-12-13 12:21:32] bar
[2011-12-13 12:22:20] baz
... где префикс - это время, когда была напечатана строка. Как мне этого добиться?
Ответы:
moreutils включает в себя,
ts
что делает это довольно хорошо:command | ts '[%Y-%m-%d %H:%M:%S]'
Это также устраняет необходимость в цикле, на каждой строке вывода будет указана временная метка.
Вы хотите знать, когда этот сервер вернулся, вы перезапустили? Просто беги
ping | ts
, проблема решена: D.источник
tail -f /tmp/script.results.txt | ts
ssh -v 127.0.0.1 2>&1 | ts
-s
полезно. Как то отображает время выполнения команды. Мне лично нравится использовать и тоts
и другоеts -s
одновременно. Выглядит примерно так:command | ts -s '(%H:%M:%.S)]' | ts '[%Y-%m-%d %H:%M:%S'
. Это добавляет строки журнала следующим образом:[2018-12-04 08:31:00 (00:26:28.267126)] Hai <3
Во-первых, если вы ожидаете, что эти временные метки действительно представляют событие, имейте в виду, что, поскольку многие программы выполняют буферизацию строки (некоторые более агрессивно, чем другие), важно думать об этом как о времени, близком к исходной линии. был напечатан, а не отметка времени происходящего действия.
Вы также можете проверить, что в вашей команде еще нет встроенной функции, предназначенной для этого. Например,
ping -D
существует в некоторыхping
версиях и печатает время с эпохи Unix перед каждой строкой. Однако, если ваша команда не содержит своего собственного метода, есть несколько методов и инструментов, которые можно использовать, среди прочего:Оболочка POSIX
Имейте в виду, что, поскольку многие оболочки хранят свои строки внутри себя как cstrings, если вход содержит нулевой символ (
\0
), это может привести к преждевременному завершению строки.GNU awk
Perl
питон
Рубин
источник
stdbuf -o 0
, но если программа вручную обрабатывает свою буферизацию вывода, это не поможет (если нет опции отключить / уменьшить размер буфера вывода).python -u
... for x in sys.stdin
перебирает строки без предварительной буферизации их всех в памяти.Для построчного измерения дельты попробуйте gnomon .
источник
ts
при использовании живых процессов. Хотяts
лучше подходит для неинтерактивных процессов.Пост Райана действительно дает интересную идею, однако, он потерпел неудачу в нескольких отношениях. Во время тестирования
tail -f /var/log/syslog | xargs -L 1 echo $(date +'[%Y-%m-%d %H:%M:%S]') $1
я заметил, что временная метка остается прежней, даже если онаstdout
появляется позже с разницей в секундах. Рассмотрим этот вывод:Мое предлагаемое решение аналогично, однако обеспечивает правильную временную отметку и использует несколько более портативный
printf
, чемecho
Почему
bash -c '...' bash
? Потому что из-за-c
опции первый аргумент присваивается$0
и не будет отображаться в выводе. Обратитесь к странице руководства вашей оболочки для правильного описания-c
Тестирование этого решения с
tail -f /var/log/syslog
отключением и (как вы, вероятно, можете догадаться) отключением и повторным подключением к моему Wi-Fi, показало правильную временную отметку, предоставляемую обоимиdate
иsyslog
сообщениями.Bash может быть заменен любым Борна типа оболочки, может быть сделано либо с
ksh
илиdash
, по крайней мере , те , которые имеют-c
опцию.Потенциальные проблемы:
Решение требует наличия
xargs
, которое доступно в POSIX-совместимых системах, поэтому большинство Unix-подобных систем должно быть охвачено. Очевидно, не будет работать, если ваша система не поддерживает POSIX или не имеетGNU findutils
источник
Я бы предпочел прокомментировать выше, но я не могу, по репутации. В любом случае, приведенный выше пример Perl может быть небуферизован следующим образом:
Первый '$ |' отстраняет STDOUT. Второй устанавливает stderr в качестве текущего выходного канала по умолчанию и снимает с него буфер. Так как select возвращает исходную настройку $ |, оборачивая select внутри select, мы также сбрасываем $ | по умолчанию STDOUT.
И да, вы можете вырезать и вставить как есть. Я разложил это на части для разборчивости.
И если вы действительно хотите получить точные данные (и у вас установлен Time :: Hires ):
источник
Большинство ответов предлагают использовать
date
, но это достаточно медленно. Если ваша версия bash больше, чем 4.2.0, лучше использоватьprintf
вместо нее встроенную версию bash. Если вам нужно поддерживать устаревшие версии bash, вы можете создатьlog
функцию в зависимости от версии bash:Смотрите различия в скорости:
UPD: вместо
$(date +"${TIMESTAMP_FORMAT}")
него лучше использовать$(exec date +"${TIMESTAMP_FORMAT}")
или даже$(exec -c date +"${TIMESTAMP_FORMAT}")
слишком ускоренное выполнение.источник
Вы можете сделать это с помощью
date
иxargs
:Объяснение:
xargs -L 1
говорит xargs запускать исходящую команду для каждой 1 строки ввода, и она передается в первой строке, как это происходит.echo `date +'[%Y-%m-%d %H:%M:%S]'` $1
в основном повторяет дату с входным аргументом в концеисточник
$1
. Это не хороший стиль. Всегда указывайте переменные. Кроме того, вы используетеecho
, который не является портативным. Это нормально, но может не работать должным образом на некоторых системах.date
переоценку каждой строки, или это в значительной степени безнадежно?