명령의 각 출력 라인에 타임 스탬프 추가 들면 다음과 같습니다. foo bar baz 될 것이다 [2011-12-13

명령의 각 출력 줄에 타임 스탬프를 추가하고 싶습니다. 예를 들면 다음과 같습니다.

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

또한 루프가 필요 없으며 모든 출력 라인에는 타임 스탬프가 붙습니다.

$ 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.


답변

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

명령에 이미 내장 기능이 없는지 확인하고 싶을 수도 있습니다. 예를 들어, 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] ")'


답변

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

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

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

gnomon demo


답변

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


답변

나는 위에서 언급하는 것을 선호했지만 평판으로는 말할 수 없습니다. 어쨌든 위의 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)'


답변

대부분의 답변은을 사용하는 것이 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}")너무 실행 속도를 높이는.


답변

당신은이 작업을 수행 할 수 있습니다 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기본적으로 마지막에 입력 인수로 날짜를 에코합니다.