“bash -x”가이 스크립트를 중단하는 이유는 무엇입니까? 스크립트가 있습니다. “실제” time명령

일부 명령이 실행되는 시간을 측정하는 스크립트가 있습니다.

“실제” time명령 이 필요합니다. 예를 들어 /usr/bin/timebash-built-in에는 -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”를 사용할 때이 스크립트가 중단되는 이유는 무엇입니까?



답변

문제는이 줄입니다.

TIMESEC=$(echo blah | ( /usr/bin/time -f %e grep blah >/dev/null ) 2>&1 | awk -F. '{print $1}')

여기서 표준 출력과 일치하도록 표준 오류를 리디렉션합니다. bash는 추적 메시지를 표준 오류에 기록하고 있으며 (예를 들어) echobash 프로세스에서 다른 쉘 구성과 함께 내장 기능을 사용하고 있습니다.

당신이 같은 것으로 변경하면

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!

답변

서브 쉘을 떨어 뜨릴 수도 있습니다. 분명히 서로를 화나게하는 중첩 된 껍질입니다.

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