bash 스크립트를 디버깅하는 방법은 무엇입니까? [닫은]


159

bash 스크립트를 디버깅하는 방법이 있습니까? 예를 들어 "calling line 1", "calling line 2"등과 같은 일종의 실행 로그를 인쇄하는 것.



답변:


195
sh -x script [arg1 ...]
bash -x script [arg1 ...]

이것들은 실행중인 것을 추적합니다. (답변 하단의 '설명'도 참조하십시오.)

때로는 스크립트 내에서 디버깅을 제어해야합니다. 이 경우 Cheeto가 상기 한 것처럼 다음을 사용할 수 있습니다.

set -x

디버깅이 켜집니다. 그런 다음 다음을 사용하여 다시 끌 수 있습니다.

set +x

$-에 대한 현재 플래그 를 분석하여 현재 추적 상태를 찾을 수 있습니다 x.

또한 쉘은 일반적으로 ' -n'실행 없음 ' 의 경우' '및 -v'세부 정보 '모드의 경우 ' ' 옵션을 제공 합니다. 이것들을 조합하여 사용하면 쉘이 스크립트를 실행할 수 있다고 생각하는지 알 수 있습니다. 어딘가에 불균형 한 인용 부호가있는 경우 유용합니다.


-xBash 의 ' '옵션이 다른 쉘과 다르다는 주장이 있습니다 (주석 참조). 배쉬 설명서는 말한다 :

  • -엑스

    간단한 명령, for명령, case명령, select명령 및 산술 for명령 및 인수 또는 관련 단어 목록을 확장 한 후 실행하기 전에 추적하십시오 . PS4변수 값 이 확장되고 결과 값이 명령 및 확장 인수 앞에 인쇄됩니다.

그다지 다른 행동을 나타내는 것은 아닙니다. -x매뉴얼 에 ' '에 대한 다른 관련 참조가 없습니다 . 시작 순서의 차이점에 대해서는 설명하지 않습니다.

설명 : 일반적인 Linux 상자와 같은 시스템에서 ' /bin/sh'는 ' '에 대한 심볼릭 링크 /bin/bash(또는 Bash 실행 파일이있는 곳)이면 두 명령 줄은 실행 추적이 설정된 상태에서 스크립트를 실행하는 것과 동일한 효과를 얻습니다. 다른 시스템 (예 : Solaris 및 일부 최신 Linux 변형)에서는 /bin/shBash가 아니며 두 명령 행은 (약간) 다른 결과를 제공합니다. 특히 ' /bin/sh'는 Bash의 구문에 의해 전혀 인식되지 않는 혼란 스러울 것입니다. (Solaris에서 /bin/shBourne 쉘이며, 현대 Linux에서는 때때로 더 작고 더 엄격하게 POSIX 전용 쉘인 Dash입니다.) 이와 같은 이름으로 'shebang'행 ( ' #!/bin/bash'vs '#!/bin/sh'

bash는 설명서에 대한 섹션이 배쉬 POSIX 모드 의 차이 '배쉬로 호출 광범위한 자세히 설명 않습니다 (아래도 의견을 참조)이 답변의 오랜하지만 잘못된 버전과 달리 sh'와 '배쉬로 호출 bash'.

(Bash) 쉘 스크립트를 디버깅 할 때 shebang 행에 이름이 지정된 쉘을 -x옵션 과 함께 사용하는 것이 합리적이고 제정신 입니다. 그렇지 않으면 스크립트를 실행할 때와 디버깅 할 때 다른 동작이 나타날 수 있습니다.


1
그는 bash스크립트를 지정했습니다 . 그리고 bash 스크립트를 실행하면 sh -x완전히 다르게 동작합니다! 답변을 업데이트하십시오.
lhunath 2016 년

1
@ lhunath : 'sh -x'(또는 'bash -x')는 어떤 방식으로 스크립트가 완전히 다르게 동작합니까? 분명히 추적 정보를 stderr에 출력합니다. 그것은 주어진 것입니다 (내 대답에는 언급되지 않았 음). 그러나 다른 무엇? Linux 및 MacOS X에서 'bash'를 'sh'로 사용하며 심각한 문제는 발견하지 못했습니다.
Jonathan Leffler 2016 년

6
시작과 런타임에 차이가 있습니다. 그것들은 Bash 배포판에 완전히 문서화되어 있습니다.
TheBonsai 2016 년

4
bash 문서에 대한 링크는 다음과 같습니다. gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files 'sh라는 이름으로 Bash를 호출하면 다음과 같이 sh의 히스토리 버전의 시작 동작을 모방하려고합니다. 가능한 한 가깝게, '뿐만 아니라 POSIX 표준에 부합하는 동안
thethinman

6
그리고 PS4 프롬프트를 사용하여 다음과 같은보다 유용한 정보를 제공하십시오.export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
estani

28

스크립트를 디버깅하기 위해 다음 방법을 사용했습니다.

set -e외부 프로그램이 0이 아닌 종료 상태를 리턴하면 스크립트가 즉시 중지됩니다. 이것은 스크립트가 모든 오류 사례를 처리하려고 시도하고 실패한 경우를 포착해야하는 경우에 유용합니다.

set -x 위에서 언급했으며 모든 디버깅 방법 중 가장 유용합니다.

set -n 스크립트에서 구문 오류를 확인하려는 경우에도 유용 할 수 있습니다.

strace무슨 일이 일어나고 있는지 볼 때도 유용합니다. 스크립트를 직접 작성하지 않은 경우 특히 유용합니다.


1
스크립트를 추적하는 것 (즉, 스크립트를 실행하는 쉘을 추적하는 것)은 이상한 쉘 디버깅 방법입니다 (그러나 제한된 문제 세트에서는 작동 할 수 있음).
TheBonsai 2016 년

1
나는 그것이 이상하고 매우 장황하다는 것을 인정하지만, strace의 출력을 몇 개의 syscall로 제한하면 유용합니다.

1
참고 strace -f당신은 또한 스크립트에 의해 시작 프로세스에서 오류를 발견 할 경우 필요합니다. (여러 번 더 장황하게 만들지 만 관심있는 syscalls로 제한하면 여전히 유용합니다).
Random832

set -e... 논쟁의 여지가 있습니다.
Charles Duffy

12

이 답변은 유효하고 유용합니다 : https://stackoverflow.com/a/951352

그러나 "표준"스크립트 디버깅 방법은 비효율적이며 직관적이지 않으며 사용하기 어렵다는 것을 알게되었습니다. 복잡한 GUI 디버거에 익숙한 사용자라면 모든 문제를 쉽게 해결할 수 있고 작업이 쉬워 쉽게 문제를 해결할 수 있습니다 (어려운 문제는 가능).

내가하는 일은 DDD와 bashdb의 조합을 사용하는 것입니다. 전자는 후자를 실행하고 후자는 스크립트를 실행합니다. 이를 통해 다중 창 UI에 컨텍스트를 유지하거나 소스를 계속 나열하려는 지속적인 정신적 노력없이 컨텍스트에서 코드를 단계별로 실행하고 변수, 스택 등을 볼 수 있습니다.

여기에 설정에 대한 지침이 있습니다 : http://ubuntuforums.org/showthread.php?t=660223


당신의 답변 덕분에 ddd를 발견했습니다. Ubuntu 12.04.3 (64 비트)에서 apt-sources 버전이 작동하지 않습니다. bash 스크립트 디버깅을 시작하려면 소스에서 컴파일 및 설치해야했습니다. 여기의 지침 -askubuntu.com/questions/156906/…이 도움이되었습니다.
chronodekar

네, 문제입니다. 내가 몇 가지 스크립트와 약간의 시간 등을 해결 - 'dddbash'을 설치합니다 / DDD 빌드, 그 잘못된 경우 이전 버전 제거 등 bashdb를 설치합니다 (대답은 지금이 정보로 편집 된)
Stabledog


10

나는 shellcheck 유틸리티를 발견했고 어떤 사람들은 그것을 재미 있다고 생각할지도 모른다 https://github.com/koalaman/shellcheck

작은 예 :

$ cat test.sh 
ARRAY=("hello there" world)

for x in $ARRAY; do
  echo $x
done

$ shellcheck test.sh 

In test.sh line 3:
for x in $ARRAY; do
         ^-- SC2128: Expanding an array without an index only gives the first element.

버그 수정, 먼저 시도해보십시오 ...

$ cat test.sh       
ARRAY=("hello there" world)

for x in ${ARRAY[@]}; do
  echo $x
done

$ shellcheck test.sh

In test.sh line 3:
for x in ${ARRAY[@]}; do
         ^-- SC2068: Double quote array expansions, otherwise they're like $* and break on spaces.

다시 해보자...

$ cat test.sh 
ARRAY=("hello there" world)

for x in "${ARRAY[@]}"; do
  echo $x
done

$ shellcheck test.sh

지금 찾으십시오!

작은 예일뿐입니다.



다행히도이 도구는 남은 버그도 발견 할 수있는 수준으로 발전했습니다.
tripleee

3

VSCode를 설치 한 다음 bash 디버그 확장을 추가하면 비주얼 모드에서 디버그 할 준비가됩니다. 실제로 여기 를 참조하십시오 .

여기에 이미지 설명을 입력하십시오


3

플러그인 쉘 및 basheclipse와 함께 이클립스를 사용하십시오.

https://sourceforge.net/projects/shelled/?source=directory https://sourceforge.net/projects/basheclipse/?source=directory

껍질이있는 경우 : zip을 다운로드하고 도움말을 통해 일식으로 가져 오기-> 새 소프트웨어 설치 : 로컬 아카이브 basheclipse의 경우 : 항아리를 일식의 dropins 디렉토리에 복사하십시오.

https://sourceforge.net/projects/basheclipse/files/?source=navbar 제공 단계를 따르십시오

여기에 이미지 설명을 입력하십시오

http://dietrichschroff.blogspot.de/2017/07/bash-enabling-eclipse-for-bash.html 에서 많은 스크린 샷이있는 자습서를 작성했습니다.


2
이것은 경계선 링크 전용 답변입니다 ( 여기 참조 ). 여기에 가능한 한 많은 정보를 포함 시키려면 최소한 제안하고있는 것을 실제로 달성하는 데 필요한 최소한의 정보를 포함하도록 답을 확장하고 링크는 참조 용으로 만 사용해야합니다. 기본적으로 스택 오버플로 및 모든 스택 교환에 대한 게시물은 독립적이어야합니다. 즉, 독자가 지시 위해 오프 사이트 필요 가 없도록 충분한 정보가 귀하의 답변에 있어야한다는 것을 의미합니다 . 지금은이 답변에 해당되지 않습니다.
Makyen

이것은 실제로 진정한 디버깅이 가능하다는 것을 보여주는 많은 것을 본 후에 찾은 첫 번째 대답입니다. 표준 답변 "set + x"는 자체 포함 된 답변과 완벽하게 일치하지만 실제 디버깅에 대한 실제 질문은 거의 의도적으로 무시합니다. 이 답변에 박수를 보냅니다 👏
simbo1905


2

+ x = @ECHO OFF로 설정하고 -x = @ECHO ON으로 설정하십시오.


-xv다음과 같이 표준 Shebang 에 옵션을 추가 할 수 있습니다 .

#!/bin/bash -xv  

-x: 명령과 인수가 실행될 때 표시합니다.
-v: 쉘 입력 라인을 읽을 때 표시합니다.


ltrace와 비슷한 다른 Linux 유틸리티 strace입니다. 그러나 ltrace실행 파일 또는 실행중인 프로세스에서 호출되는 모든 라이브러리 호출을 나열합니다. 이름 자체는 라이브러리 호출 추적에서 비롯됩니다. 예를 들면 다음과 같습니다.

ltrace ./executable <parameters>  
ltrace -p <PID>  

출처



1

디버깅하는 몇 가지 트릭 스크립트 :

사용 set -[nvx]

이외에

set -x

set +x

덤프를 중지합니다.

set -v덜 개발 된 출력만큼 ​​작은 덤프 에 대해 이야기하고 싶습니다 .

bash <<<$'set -x\nfor i in {0..9};do\n\techo $i\n\tdone\nset +x' 2>&1 >/dev/null|wc -l
21

for arg in x v n nx nv nvx;do echo "- opts: $arg"
    bash 2> >(wc -l|sed s/^/stderr:/) > >(wc -l|sed s/^/stdout:/) <<eof
        set -$arg
        for i in {0..9};do
            echo $i
          done
        set +$arg
        echo Done.
eof
    sleep .02
  done
- opts: x
stdout:11
stderr:21
- opts: v
stdout:11
stderr:4
- opts: n
stdout:0
stderr:0
- opts: nx
stdout:0
stderr:0
- opts: nv
stdout:0
stderr:5
- opts: nvx
stdout:0
stderr:5

변수 덤프 또는 즉시 추적

일부 변수를 테스트하기 위해 언젠가 이것을 사용합니다.

bash <(sed '18ideclare >&2 -p var1 var2' myscript.sh) args

추가를 위해 :

declare >&2 -p var1 var2

18 번째 줄에서 스크립트 를 편집하지 않고도 결과 스크립트 ( args 사용 )를 실행 합니다.

물론 이것은 다음을 추가하는 데 사용될 수 있습니다 set [+-][nvx].

bash <(sed '18s/$/\ndeclare -p v1 v2 >\&2/;22s/^/set -x\n/;26s/^/set +x\n/' myscript) args

declare -p v1 v2 >&2줄 18 뒤에, set -x줄 22와 set +x줄 26 앞에 추가됩니다 .

작은 샘플 :

bash <(sed '2,3s/$/\ndeclare -p LINENO i v2 >\&2/;5s/^/set -x\n/;7s/^/set +x\n/' <(
        seq -f 'echo $@, $((i=%g))' 1 8)) arg1 arg2
arg1 arg2, 1
arg1 arg2, 2
declare -i LINENO="3"
declare -- i="2"
/dev/fd/63: line 3: declare: v2: not found
arg1 arg2, 3
declare -i LINENO="5"
declare -- i="3"
/dev/fd/63: line 5: declare: v2: not found
arg1 arg2, 4
+ echo arg1 arg2, 5
arg1 arg2, 5
+ echo arg1 arg2, 6
arg1 arg2, 6
+ set +x
arg1 arg2, 7
arg1 arg2, 8

참고 : 주의 사항 $LINENO즉석 수정 으로 인해 영향을받습니다 !

(실행하는 동안 결과 스크립트를 보려면 간단히 삭제 bash <(하고 ) arg1 arg2)

단계별, 실행 시간

bash 스크립트를 프로파일 링하는 방법에 대한 내 대답을 살펴보십시오.


0

셸의 전역 변수를 통한 셸 스크립트 로깅에 대한 자세한 내용이 있습니다. 쉘 스크립트에서 비슷한 종류의 로깅을 에뮬레이트 할 수 있습니다 : http://www.cubicrace.com/2016/03/log-tracing-mechnism-for-shell-scripts.html

이 게시물에는 INFO, DEBUG, ERROR와 같은 로그 수준 소개에 대한 세부 정보가 있습니다. 스크립트 입력, 스크립트 종료, 기능 입력, 기능 종료와 같은 세부 사항 추적

샘플 로그 :

여기에 이미지 설명을 입력하십시오

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