나는 표준 입력의 각 줄 앞에 표준 입력을 생성하는 데 걸린 시간에 대한 정보를 추가하는 스크립트를 원합니다. 기본적으로 입력용:
foo
bar
baz
가지고 싶다
0 foo
10 bar
5 baz
10은 foo를 인쇄하고 bar를 인쇄하는 데 걸리는 10초입니다. 5와 마찬가지로 bar를 인쇄한 후 baz를 인쇄하는 데 5초가 걸립니다.
ts
타임스탬프를 표시할 수 있는 유틸리티가 있다는 것을 알고 있습니다 .https://github.com/paypal/gnomon, 하지만 이 작업을 수행하기 위해 자바스크립트를 사용하고 싶지 않습니다.
표준 도구가 있습니까? 아니면 이를 위해 awk를 사용해야 합니까?
답변1
출력을 생성하는 스크립트가 이라고 가정합니다 generate
. 그런 다음 각 행을 생성하는 데 걸리는 시간(초)을 표시합니다.
$ generate | ( t0=$(date +%s); while read -r line; do t1=$(date +%s); echo " $((t1-t0)) $line"; t0=$t1; done )
2 foo
0 foo
5 foo
3 foo
여러 줄에 걸쳐 있는 동일한 명령은 다음과 같습니다.
generate | ( t0=$(date +%s)
while read -r line
do
t1=$(date +%s)
echo " $((t1-t0)) $line"
t0=$t1
done
)
또는 편의를 위해 다음 코드를 포함하는 셸 함수를 정의할 수 있습니다.
timer() { t0=$(date +%s); while read -r line; do t1=$(date +%s); echo " $((t1-t0)) $line"; t0=$t1; done; }
이 기능을 다음과 같이 사용할 수 있습니다.
$ generate | timer
0 foo
2 foo
4 foo
3 foo
어떻게 작동하나요?
t0=$(date +%s)
스크립트가 시작된 현재 시간을 초 단위로 캡처합니다.
while read -r line; do
표준 입력에서 루프 읽기가 시작됩니다.
t1=$(date +%s)
이는 현재 행이 캡처된 이후의 시간(초)을 캡처합니다.
echo " $((t1-t0)) $line"
현재 행에 걸린 시간을 초 단위로 인쇄합니다.
t0=$t1
그러면
t0
다음 행이 업데이트됩니다.done
이것은 주기의 끝을 표시합니다
while
.
답변2
trickle () {
awk 'BEGIN { t = systime(); OFS="\t" }
{ print systime() - t, $0 }
{ t = systime() }'
}
이 작은 쉘 함수는 단지 awk
스크립트를 래핑합니다(GNU 및 GNU와 호환되지만 awk
BSD mawk -Wi
가 부족하여 BSD와 호환되지 않음). 마지막 출력 줄 이후 전체 초 수를 앞에 붙여 각 입력 줄을 출력합니다. 첫 번째 줄에는 0이 앞에 붙습니다.awk
systime()
시험:
$ { echo hello; sleep 2; echo world } | trickle
0 hello
2 world
스크립트 awk
는 독립형으로 실행될 수도 있습니다.
$ some_command | awk 'BEGIN{OFS="\t";t=systime()}{print systime()-t,$0;t=systime()}
예를 들어
$ { echo hello; sleep 2; echo world; } | awk 'BEGIN{OFS="\t";t=systime()}{print systime()-t,$0;t=systime()}'
0 hello
2 world
답변3
훌륭한,더 많은 유틸리티 ts
완벽한 도구인 것 같습니다.
시작 후 초:
$ seq 5 | pv -qL 1 | ts -s %s
2 1
4 2
6 3
8 4
10 5
또는 더 정확하게는:
$ seq 5 | pv -qL 1 | ts -s %.s
1.949228 1
3.933483 2
5.917923 3
7.902231 4
9.886618 5
또는 zsh
또는를 사용하십시오 ksh93
( $SECONDS
기본값은 정수이지만;를 사용하여 부동 소수점으로 만들 수도 있습니다. typeset -F
이 pdksh
역시 bash
작동 $SECONDS
하지만 정수에만 해당됩니다).
$ typeset -F SECONDS=0; seq 5 | pv -qL 1 | while IFS= read -r line; do
printf '%.3f %s\n' "$SECONDS" "$line"; done
1.987 1
3.972 2
5.956 3
7.941 4
9.925 5
행 사이의 초 수
$ seq 5 | pv -qL 1 | ts -i %.s
1.947814 1
1.984442 2
1.984456 3
1.984151 4
1.984195 5
zsh
/ ksh93
:
$ typeset -F SECONDS; seq 5 | pv -qL 1 | while SECONDS=0; IFS= read -r line; do
printf '%.6f %s\n' "$SECONDS" "$line"; done
1.985298 1
1.984322 2
1.984212 3
1.984240 4
1.984441 5
답변4
먼저 bash 내장 함수를 사용하여 간단한 함수를 만듭니다 SECONDS
. 모든 호출에서 이를 0으로 초기화한다는 점에 유의하세요.
_time() { SECONDS=0; out="$($@)"; echo "[${SECONDS}] ${out:-no output}"; }
다음으로, 이 _time
함수를 사용하여 명령 목록(명령 파일 등)에서 명령을 실행합니다.
while read cmd; do _time $cmd; done < <(echo -e "sleep 5\nsleep 2\nsleep 1")
여기서 sleep에는 출력이 없지만 명령은 출력될 수 있습니다. 이는 이 질문과 관련된 SECONDS의 사용을 보여주기 위한 것입니다. 이 예에서는 다음과 같은 기본 출력을 출력합니다 no output
.
[5] no output
[2] no output
[1] no output