특정 명령을 실행하는 데 걸리는 시간을 측정하는 스크립트가 있습니다.
time
"실제" 명령, 즉 바이너리가 필요합니다 /usr/bin/time
(bash 내장에는 해당 플래그가 없기 때문입니다 -f
).
디버깅할 수 있는 단순화된 스크립트는 다음과 같습니다.
#!/bin/bash
TIMESEC=$(echo blah | ( /usr/bin/time -f %e grep blah >/dev/null ) 2>&1 | awk -F. '{print $1}')
echo ABC--$TIMESEC--DEF
if [ "$TIMESEC" -eq 0 ] ; then
echo "we are here!"
fi
"test.sh"로 저장하고 다음을 실행합니다.
$ bash test.sh
ABC--0--DEF
we are here!
그래서 작동합니다.
이제 bash 명령줄에 "-x"를 추가하여 디버깅해 보겠습니다.
$ bash -x test.sh
++ echo blah
++ awk -F. '{print $1}'
+ TIMESEC='++ /usr/bin/time -f %e grep blah
0'
+ echo ABC--++ /usr/bin/time -f %e grep blah 0--DEF
ABC--++ /usr/bin/time -f %e grep blah 0--DEF
+ '[' '++ /usr/bin/time -f %e grep blah
0' -eq 0 ']'
test.sh: line 10: [: ++ /usr/bin/time -f %e grep blah
0: integer expression expected
"-x"를 사용하면 이 스크립트가 중단되지만, "-x" 없이는 잘 작동하는 이유는 무엇입니까?
답변1
문제는 다음 줄입니다.
TIMESEC=$(echo blah | ( /usr/bin/time -f %e grep blah >/dev/null ) 2>&1 | awk -F. '{print $1}')
표준 출력과 일치하도록 표준 오류를 리디렉션하고 있습니다. bash는 표준 오류에 대한 추적 메시지를 작성하고 (예를 들어) bash 프로세스 내의 내장 함수 echo
및 기타 쉘 구성을 사용합니다.
다음과 같은 것으로 바꾸면
TIMESEC=$(echo blah | sh -c "( /usr/bin/time -f %e grep blah >/dev/null )" 2>&1 | awk -F. '{print $1}')
이는 이 문제를 해결하고 추적과 작업 사이에서 허용 가능한 절충안이 될 수 있습니다.
++ awk -F. '{print $1}'
++ sh -c '( /usr/bin/time -f %e grep blah >/dev/null )'
++ echo blah
+ TIMESEC=0
+ echo ABC--0--DEF
ABC--0--DEF
+ '[' 0 -eq 0 ']'
+ echo 'we are here!'
we are here!
답변2
서브쉘을 직접 삭제할 수도 있습니다. 분명히 서로 화나게 되는 것은 중첩된 껍질입니다.
TIMESEC=$(
echo blah |
/usr/bin/time -f %e grep blah 2>&1 >/dev/null |
awk -F. '{print $1}'
)
이렇게 하면:
...| ( subshell ) 2>pipe | ...
...파이프라인의 해당 부분을 처리하기 위해 서브셸을 실행하게 됩니다.호스팅내부의 서브쉘입니다. 쉘은 서브쉘의 디버그 출력을 리디렉션하지도 않기 때문에( 사용하기로 선택할 수 있는 다른 종류의 {
복합 명령 에서도 작동합니다); } >redirect
파이프 섹션에서 흐름을 혼합합니다. 리디렉션 순서와 관련이 있습니다.
대신 먼저 리디렉션하면오직측정하려는 명령의 오류 출력을 갖고 호스트 셸의 출력이 이를 stderr로 보내도록 하면 동일한 문제가 발생하지 않습니다.
그래서...
... | command 2>pipe 1>/dev/null | ...
...호스트 셸은 원하는 곳 어디에서나 stderr에 자유롭게 계속 쓸 수 있으며 호출하는 명령의 출력만 파이프로 리디렉션합니다.
bash -x time.sh
+++ echo blah
+++ /usr/bin/time -f %e grep blah
+++ awk -F. '{print $1}'
++ TIMESEC=0
++ echo ABC--0--DEF
ABC--0--DEF
++ '[' 0 -eq 0 ']'
++ echo 'we are here!'
we are here!
이 질문에 대해서...
TIMESEC=$(
echo blah |
/usr/bin/time -f %e grep blah 2>&1 >/dev/null
)
printf %s\\n "ABC--${TIMESEC%%.*}--DEF"
if [ "${TIMESEC%%.*}" -eq 0 ] ; then
echo "we are here!"
fi