명령의 각 출력 라인에 타임 스탬프 추가


답변:


274

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.


8
나는 이것에 대해 어떻게 알지 못했습니까?!?!?! 이것은 놀랍게도 tail -f를 보완합니다! tail -f /tmp/script.results.txt | ts
Bruno Bronosky

cygwin은 어떻습니까? 비슷한 것이 있습니까? Joey의 moreutils가있는 것처럼 보이지 않습니다.
CrazyPenguin

3
ts 명령이 없으면 무엇을 사용해야합니까?
ekassis

1
작동하지 않으면 stderr를 stdout으로 리디렉션하십시오.ssh -v 127.0.0.1 2>&1 | ts
jchook

3
매개 변수를 지적하는 -s것이 유용 하다고 생각 합니다. 명령의 런타임이 표시됩니다. 나는 개인적으로 모두 사용 같은 tsts -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
BrainStone

100

첫째, 이러한 타임 스탬프가 실제로 이벤트를 나타낼 것으로 예상되는 경우 많은 프로그램이 라인 버퍼링을 수행하기 때문에 (다른 것보다 더 적극적으로),이를 원래 라인의 시간에 가깝게 생각하는 것이 중요합니다. 액션 타임 스탬프가 아닌 인쇄되었습니다.

명령에 이미 내장 기능이 없는지 확인하고 싶을 수도 있습니다. 예를 들어, ping -D일부 ping버전에 존재하며 각 라인 앞에 유닉스 시대 이후의 시간을 인쇄합니다. 그러나 명령에 고유 한 방법이 포함되어 있지 않은 경우 사용할 수있는 몇 가지 방법과 도구가 있습니다.

POSIX 쉘

많은 쉘이 문자열을 내부적으로 cstring으로 저장하므로 입력에 널 문자 ( \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 }'

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

파이썬

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 )))'

루비

command | ruby -pe 'print Time.now.strftime("[%Y-%m-%d %H:%M:%S] ")'

3
여기서 한 가지 문제는 많은 프로그램이 stdout이 터미널 대신 파이프 인 경우 더 많은 출력 버퍼링을 설정한다는 것입니다.
CJM

3
@cjm-맞습니다. 을 사용하여 일부 출력 버퍼링을 완화 할 수 stdbuf -o 0있지만 프로그램이 출력 버퍼링을 수동으로 처리하는 경우 도움이되지 않습니다 (출력 버퍼의 크기를 비활성화 / 축소하는 옵션이없는 한).
Chris Down

2
파이썬의 경우와 라인 버퍼링을 해제 할 수 있습니다python -u
ibizaman

@Bwmat No.는 ... for x in sys.stdin먼저 메모리에 모두 버퍼링하지 않고 행을 반복합니다.
Chris Down

이 작업을 수행하면 버퍼링이 생깁니다. 1 in 1 1 1 1; 잠을 1; 에코; 완료 | python -c 'import sys, time; sys.stdout.write ( "". join (( "".join ((time.strftime ( "[% Y- % m- % d % H : % M : % S]) ", time.gmtime ()), line)) sys.stdin의 line))) ''
ChuckCottrill

41

라인 별 델타 측정의 경우 gnomon을 시도하십시오 .

타임 스탬프 정보를 다른 명령의 표준 출력에 추가하는 것은 moreutils의 ts와 비슷한 명령 행 유틸리티입니다. 오래 걸리는 것에 대한 역사적 기록을 원하는 장기 실행 프로세스에 유용합니다.

gnomon에 아무것도 파이프하면 각 라인에 타임 스탬프가 추가되어 해당 라인이 버퍼의 마지막 라인이었던 시간, 즉 다음 라인이 나타나는 데 걸린 시간을 나타냅니다. 기본적으로 gnomon은 각 줄 사이에 경과 된 초를 표시하지만 구성 할 수 있습니다.

gnomon demo


ts라이브 프로세스 를 사용할 때 의 훌륭한 대안처럼 보입니다 . 동안은 ts비 대화 형 프로세스에 더 적합하다.
BrainStone

7

Ryan의 게시물은 흥미로운 아이디어를 제공하지만 여러 측면에서 실패합니다. 로 테스트하는 동안 나중에 초 단위로 차이가 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내 무선 랜에 연결을 끊었다가 다시 연결 하여이 솔루션을 테스트하면 메시지 datesyslog메시지 모두에서 올바른 타임 스탬프가 표시됩니다.

배쉬는 bourne 같은 쉘로 대체 될 수 있으며 적어도 옵션 이있는 쉘로 ksh또는 으로 수행 할 수 있습니다 .dash-c

잠재적 인 문제 :

이 솔루션에는 xargsPOSIX 호환 시스템에서 사용할 수있는가 있어야하므로 대부분의 유닉스 계열 시스템이 포함되어야합니다. 시스템이 POSIX 호환이 아니거나 시스템이 없으면 작동하지 않습니다.GNU findutils


5

나는 위에서 언급하는 것을 선호했지만 평판으로는 말할 수 없습니다. 어쨌든 위의 Perl 샘플은 다음과 같이 버퍼링되지 않을 수 있습니다.

command | perl -pe 'use POSIX strftime; 
                    $|=1; 
                    select((select(STDERR), $| = 1)[0]);
                    print strftime "[%Y-%m-%d %H:%M:%S] ", localtime'

첫 번째 '$ |' STDOUT의 버퍼를 해제합니다. 두 번째는 stderr을 현재 기본 출력 채널로 설정하고 버퍼링을 해제합니다. select는 select를 원래 안에 래핑함으로써 $ |의 원래 설정을 반환하므로 $ |도 재설정합니다. 기본값 인 STDOUT으로 설정하십시오.

그리고 네, 페이스트를 그대로자를 수 있습니다. 가독성을 위해 여러 줄로 표시했습니다.

그리고 정말로 정확하게 알고 싶다면 Time :: Hires가 설치되어 있습니다.

command | perl -pe 'use POSIX strftime; use Time::HiRes gettimeofday;
                    $|=1; 
                    select((select(STDERR), $| = 1)[0]);
                    ($s,$ms)=gettimeofday();
                    $ms=substr(q(000000) . $ms,-6);
                    print strftime "[%Y-%m-%d %H:%M:%S.$ms]", localtime($s)'

1
비표준 패키지를 설치하지 않고도 매력처럼 작동합니다.
Jay Taylor

2

대부분의 답변은을 사용하는 것이 date좋지만 속도가 느립니다. bash 버전이 4.2.0보다 큰 경우 printf대신 bash 를 사용 하는 것이 좋습니다 . 레거시 bash 버전을 지원해야하는 경우 bash 버전에 log따라 함수 를 작성할 수 있습니다 .

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}")너무 실행 속도를 높이는.


0

당신은이 작업을 수행 할 수 있습니다 datexargs:

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

설명:

xargs -L 1xargs에게 1 행의 입력마다 진행 명령을 실행하도록 지시하고, 첫 번째 행을 통과합니다. echo `date +'[%Y-%m-%d %H:%M:%S]'` $1기본적으로 마지막에 입력 인수로 날짜를 에코합니다.


2
솔루션이 가까이 있지만 출력이 오랜 시간 분리되어 올 때 타임 스탬프가 적절하지 않습니다. 또한, 당신은 백틱을 사용하고 있으며 인용하지 않았습니다 $1. 좋은 스타일이 아닙니다. 항상 변수를 인용하십시오. 또한 echo휴대용이 아닌을 사용 하고 있습니다. 문제는 없지만 일부 시스템에서는 제대로 작동하지 않을 수 있습니다.
Sergiy Kolodyazhnyy

이것을 테스트 한 후, 당신이 절대적으로 옳은 것처럼 보입니다 ... date모든 라인을 재평가 할 수 있는 방법을 알고 있습니까? 아니면 거의 희망이 없습니까?
Ryan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.