각 줄 앞에 해당 줄을 생성하는 데 걸린 시간을 추가하세요.

각 줄 앞에 해당 줄을 생성하는 데 걸린 시간을 추가하세요.

나는 표준 입력의 각 줄 앞에 표준 입력을 생성하는 데 걸린 시간에 대한 정보를 추가하는 스크립트를 원합니다. 기본적으로 입력용:

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와 호환되지만 awkBSD mawk -Wi가 부족하여 BSD와 호환되지 않음). 마지막 출력 줄 이후 전체 초 수를 앞에 붙여 각 입력 줄을 출력합니다. 첫 번째 줄에는 0이 앞에 붙습니다.awksystime()

시험:

$ { 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 -Fpdksh역시 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

관련 정보