“bash -x”가이 스크립트를 중단하는 이유는 무엇입니까?


13

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

"실제" 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"를 사용할 때이 스크립트가 중단되는 이유는 무엇입니까?


1
허. -xon 과 같이 $()구성이 -x결과 값의 일부로 출력을 포함 시키는 것으로 보입니다 . "예상 된"동작인지 버그인지 모르지만 ... ()실제로 -x출력을 제공하는 서브 쉘일 수도 있습니다 .
— Jeff Y

옆으로 : 설정 BASH_XTRACEFD하면 set -x문제가 덜 발생하는 곳으로 출력을 리디렉션 할 수 있습니다 .
— Charles Duffy

답변:


21

문제는이 줄입니다.

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!

7

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

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.