วิธีการดีบักสคริปต์ทุบตี? [ปิด]


159

มีวิธีการดีบักสคริปต์ทุบตีหรือไม่? เช่นบางอย่างที่พิมพ์บันทึกการดำเนินการเช่น "การโทรสาย 1", "การโทร 2 บรรทัด" เป็นต้น



นี่อาจจะเป็นอีกคนหนึ่งที่ซ้ำกัน
Pablo A

คำตอบ:


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

สิ่งเหล่านี้ทำให้คุณมีร่องรอยของสิ่งที่กำลังดำเนินการ (ดู 'การชี้แจง' ใกล้ด้านล่างของคำตอบ)

บางครั้งคุณต้องควบคุมการดีบักภายในสคริปต์ ในกรณีนั้นตามที่Cheeto เตือนฉันคุณสามารถใช้:

set -x

สิ่งนี้จะเปิดการดีบัก จากนั้นคุณสามารถปิดได้อีกครั้งด้วย:

set +x

(คุณสามารถค้นหาสถานะการติดตามปัจจุบันโดยการวิเคราะห์$-สถานะปัจจุบันสำหรับx)

นอกจากนี้เชลล์โดยทั่วไปยังมีตัวเลือก ' -n' สำหรับ 'ไม่มีการประมวลผล' และ ' -v' สำหรับโหมด 'verbose' คุณสามารถใช้สิ่งเหล่านี้ร่วมกันเพื่อดูว่าเชลล์คิดว่ามันสามารถรันสคริปต์ของคุณได้หรือไม่ - บางครั้งก็มีประโยชน์ถ้าคุณมีคำพูดที่ไม่สมดุล


มีข้อโต้แย้งว่า-xตัวเลือก '' ใน Bash นั้นแตกต่างจาก shell อื่น ๆ (ดูความคิดเห็น) คู่มือทุบตีพูดว่า:

  • -x

    พิมพ์การติดตามของคำสั่งคำสั่งคำforสั่งcaseคำselectสั่งและforคำสั่งทางคณิตศาสตร์และอาร์กิวเมนต์หรือรายการคำที่เกี่ยวข้องหลังจากที่พวกเขาถูกขยายและก่อนที่พวกเขาจะถูกดำเนินการ ค่าของPS4ตัวแปรถูกขยายและค่าผลลัพธ์จะถูกพิมพ์ก่อนคำสั่งและอาร์กิวเมนต์ที่ขยายเพิ่ม

สิ่งนั้นดูเหมือนจะไม่ได้บ่งบอกถึงพฤติกรรมที่แตกต่างกันเลย ฉันไม่เห็นข้อมูลอ้างอิงอื่นที่เกี่ยวข้องกับ ' -x' ในคู่มือ ไม่ได้อธิบายความแตกต่างในลำดับการเริ่มต้น

การชี้แจง : ในระบบเช่นกล่อง Linux ทั่วไปโดยที่ ' /bin/sh' คือ symlink ไปที่ ' /bin/bash' (หรือที่ใดก็ตามที่พบ Bash ที่ปฏิบัติการได้) บรรทัดคำสั่งสองบรรทัดจะให้ผลเทียบเท่ากับการรันสคริปต์โดยมีการติดตามการเรียกใช้งาน บนระบบอื่น (ตัวอย่างเช่น Solaris และ Linux สมัยใหม่บางรุ่น) /bin/shไม่ใช่ Bash และบรรทัดคำสั่งสองบรรทัดจะให้ผลลัพธ์ที่แตกต่างกันเล็กน้อย (เล็กน้อย) ที่สะดุดตาที่สุด ' /bin/sh' จะสับสนโดยการสร้างใน Bash ที่มันไม่รู้จักเลย (บน Solaris /bin/shเป็น Bourne shell; ใน Linux รุ่นใหม่บางครั้งมันก็เป็น Dash - ซึ่งเป็นขนาดเล็กกว่า POSIX-only shell เท่านั้น) เมื่อเรียกด้วยชื่อเช่นนี้บรรทัด 'shebang' (' #!/bin/bash' vs '#!/bin/sh'

คู่มือทุบตีมีส่วนในโหมดทุบตี POSIXซึ่งตรงกันข้ามกับคำตอบนี้รุ่นยาว แต่ผิดพลาด (ดูความคิดเห็นด้านล่าง) อธิบายรายละเอียดที่แตกต่างระหว่าง 'ทุบตีเรียกว่าเป็นsh' และ 'ทุบตีเรียกว่าเป็นbash'

เมื่อทำการดีบักเชลล์สคริปต์ (Bash) มันจะสมเหตุสมผลและมีสติ - จำเป็นแม้กระทั่ง - เพื่อใช้เชลล์ที่มีชื่อในบรรทัด Shebang พร้อม-xตัวเลือก มิฉะนั้นคุณอาจจะได้รับพฤติกรรมที่แตกต่างกันเมื่อทำการดีบั๊กเมื่อรันสคริปต์


1
เขาระบุbashสคริปต์ และการใช้สคริปต์ทุบตีsh -xจะทำให้มันทำงานแตกต่างไปจากเดิมอย่างสิ้นเชิง! โปรดอัปเดตคำตอบของคุณ
lhunath

1
@lhunath: 'sh -x' (หรือ 'bash -x') ทำให้สคริปต์ทำงานแตกต่างกันโดยสิ้นเชิงอย่างไร? เห็นได้ชัดว่ามันส่งออกข้อมูลการติดตามไปยัง stderr; ที่ได้รับ (แต่ไม่ได้กล่าวถึงในคำตอบของฉัน) แต่มีอะไรอีกบ้าง? ฉันใช้ 'bash' เป็น 'sh' บน Linux และ MacOS X และไม่พบว่ามีปัญหาร้ายแรง
Jonathan Leffler

6
มีความแตกต่างในการเริ่มต้นและภายใต้รันไทม์ เอกสารเหล่านี้ได้รับการบันทึกอย่างครบถ้วนในการแจกจ่าย Bash
TheBawai

4
นี่คือลิงค์ไปยัง bash doc: gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files 'ถ้า Bash ถูกเรียกด้วยชื่อ sh มันจะพยายามเลียนแบบพฤติกรรมการเริ่มต้นของ sh รุ่นที่ผ่านมาเช่น อย่างใกล้ที่สุดเท่าที่เป็นไปได้ในขณะที่สอดคล้องกับมาตรฐาน posix เช่นกัน '
thethinman

6
และใช้พรอมต์ PS4 เพื่อให้ข้อมูลที่เป็นประโยชน์มากขึ้นเช่น:export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
estani

28

ฉันใช้วิธีต่อไปนี้เพื่อดีบักสคริปต์ของฉัน

set -eทำให้สคริปต์หยุดทำงานทันทีหากโปรแกรมภายนอกใด ๆ ส่งคืนสถานะการออกที่ไม่ใช่ศูนย์ สิ่งนี้มีประโยชน์หากสคริปต์ของคุณพยายามจัดการกรณีที่มีข้อผิดพลาดทั้งหมดและในกรณีที่ควรติดกับดัก

set -x ถูกกล่าวถึงข้างต้นและแน่นอนมีประโยชน์มากที่สุดของวิธีการตรวจแก้จุดบกพร่องทั้งหมด

set -n อาจมีประโยชน์หากคุณต้องการตรวจสอบข้อผิดพลาดทางไวยากรณ์ของสคริปต์

straceยังเป็นประโยชน์ในการดูว่าเกิดอะไรขึ้น มีประโยชน์อย่างยิ่งหากคุณยังไม่ได้เขียนสคริปต์ด้วยตัวเอง


1
การบีบอัดสคริปต์ (เช่นการบีบอัดเชลล์เพื่อเรียกใช้งานสคริปต์) เป็นวิธีการดีบักเชลล์แปลก ๆ (แต่อาจใช้ได้กับปัญหาที่ จำกัด )
TheBonsai

1
ฉันยอมรับว่ามันแปลกและ verbose มาก แต่ถ้าคุณ จำกัด เอาท์พุทของ strace ไปยังตึกระฟ้าไม่กี่แห่งมันจะมีประโยชน์

1
โปรดทราบว่าstrace -fจำเป็นหากคุณต้องการค้นหาข้อผิดพลาดในกระบวนการที่เริ่มต้นโดยสคริปต์ (ซึ่งจะทำให้ verbose มากขึ้นหลายครั้ง แต่ก็ยังมีประโยชน์ถ้าคุณ จำกัด ให้ syscalls ที่คุณสนใจ)
Random832

set -eมีที่ ... ที่ถกเถียงกัน
Charles Duffy

12

คำตอบนี้ถูกต้องและมีประโยชน์: https://stackoverflow.com/a/951352

แต่ฉันพบว่าวิธีการตรวจแก้จุดบกพร่องสคริปต์ "มาตรฐาน" นั้นไม่มีประสิทธิภาพใช้งานง่ายและใช้งานยาก สำหรับผู้ที่เคยใช้ดีบั๊ก GUI ที่ซับซ้อนซึ่งทำให้ทุกอย่างอยู่ใกล้แค่ปลายนิ้วของคุณและทำให้งานง่ายขึ้นสำหรับปัญหาง่าย ๆ

สิ่งที่ฉันทำคือใช้การรวมกันของ DDD และ bashdb อดีตดำเนินการหลังและหลังรันสคริปต์ของคุณ สิ่งนี้ให้ UI หลายหน้าต่างที่มีความสามารถในการก้าวผ่านโค้ดในบริบทและดูตัวแปรสแต็ก ฯลฯ โดยไม่ต้องใช้ความพยายามอย่างต่อเนื่องเพื่อรักษาบริบทในหัวของคุณหรือเก็บรายการแหล่งที่มาอีกครั้ง

มีคำแนะนำในการตั้งค่าที่นี่: http://ubuntuforums.org/showthread.php?t=660223


เพิ่งค้นพบววขอบคุณคำตอบของคุณ ใน Ubuntu 12.04.3 (64 บิต) รุ่น apt-source ไม่ทำงาน ฉันต้องรวบรวม & ติดตั้งจากซอร์สเพื่อเริ่มการดีบักสคริปต์ทุบตีของฉัน คำแนะนำที่นี่ - askubuntu.com/questions/156906/…ช่วย
chronodekar

ใช่นั่นเป็นปัญหา ฉันแก้ไขมันบางเวลากลับมาพร้อมกับสคริปต์ - 'dddbash' ติดตั้ง / สร้าง DDD ลบรุ่นเก่าถ้ามันผิดติดตั้ง bashdb ฯลฯ (คำตอบได้รับการแก้ไขด้วยข้อมูลนี้ตอนนี้)
Stabledog

10

นอกจากนี้คุณยังสามารถเขียน "set -x" ภายในสคริปต์


4
และคุณสามารถเขียน 'set + x' เพื่อปิด
Jonathan Leffler

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

หาตอนนี้!

มันเป็นเพียงตัวอย่างเล็ก ๆ


1
และมันออนไลน์ !
Nick Westgate

โชคดีที่เครื่องมือได้พัฒนาจนถึงจุดที่พบข้อผิดพลาดที่เหลืออยู่
tripleee

3

ติดตั้งVSCodeจากนั้นเพิ่ม bash debug extension และคุณพร้อมที่จะทำการ debug ในโหมด visual ดูที่นี่ในการดำเนินการ

ป้อนคำอธิบายรูปภาพที่นี่


3

ใช้ eclipse กับปลั๊กอินที่มีเปลือก & basheclipse

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

สำหรับ shelled: ดาวน์โหลด zip และนำเข้าสู่ eclipse ผ่านวิธีใช้ -> ติดตั้งซอฟต์แวร์ใหม่: ไฟล์เก็บถาวรสำหรับ basheclipse: คัดลอก jars ไปยังไดเร็กทอรี dropins ของ eclipse

ทำตามขั้นตอนที่ให้https://sourceforge.net/projects/basheclipse/files/?source=navbar

ป้อนคำอธิบายรูปภาพที่นี่

ฉันเขียนบทช่วยสอนที่มีภาพหน้าจอมากมายที่http://dietrichschroff.blogspot.de/2017/07/bash-enabling-eclipse-for-bash.html


2
นี่คือคำตอบสำหรับลิงก์แบบเส้นขอบเท่านั้น (ดูที่นี่ด้วย ) คุณควรขยายคำตอบของคุณเพื่อรวมข้อมูลให้มากที่สุดเท่าที่จะเป็นไปได้อย่างน้อยที่สุดขั้นต่ำที่จำเป็นในการบรรลุสิ่งที่คุณแนะนำและใช้ลิงก์เพื่อการอ้างอิงเท่านั้น โดยทั่วไปโพสต์ใน Stack Overflow (และทั้งหมดของ Exchange Exchange) ต้องอยู่ในตัวเอง นั่นหมายความว่าต้องมีข้อมูลเพียงพอในคำตอบของคุณซึ่งผู้อ่านไม่จำเป็นต้องออกนอกเส้นทางเพื่อขอคำแนะนำ ตอนนี้ไม่ใช่กรณีของคำตอบนี้
Makyen

นี่เป็นคำตอบแรกที่ฉันได้พบหลังจากดูหลายอย่างที่แสดงให้เห็นว่าการดีบักที่แท้จริงนั้นเป็นไปได้ คำตอบมาตรฐาน "set + x" ตรงกับคำตอบที่มีอยู่ในตัวเองอย่างสมบูรณ์แบบ แต่เกือบจะไม่สนใจคำถามที่แท้จริงเกี่ยวกับการดีบักจริง ฉันปรบมือให้คำตอบนี้👏
simbo1905

2

ฉันสร้างดีบักเกอร์ Bash แค่ลองดู ฉันหวังว่ามันจะช่วย https://sourceforge.net/projects/bashdebugingbash


ขณะนี้ BDB รองรับภาษาอังกฤษและสเปน หากต้องการเปลี่ยนภาษาให้แก้ไขไฟล์ / etc / default / bdb
abadjm

ภาพหน้าจอดูน่าสนใจ แต่ฉันไม่สามารถเรียกใช้ "bdb.sh: line 32: bdbSTR [1]: ตัวแปรที่ไม่ได้ผูก"; btw จะแสดงค่าปัจจุบันของตัวแปรทั้งหมดที่ตั้งไว้ในแต่ละขั้นตอนที่เราทำกับโค้ดหรือไม่
อำนาจกุมภ์

2

set + x = @ECHO OFF ตั้ง -x = @ECHO ON


คุณสามารถเพิ่ม-xvตัวเลือกใน Shebang มาตรฐานดังต่อไปนี้:

#!/bin/bash -xv  

-x: แสดงคำสั่งและข้อโต้แย้งขณะดำเนินการ
-v: แสดงบรรทัดอินพุตเชลล์ขณะที่อ่าน


ltracestraceเป็นอีกหนึ่งลินุกซ์ยูทิลิตี้ที่คล้ายกัน อย่างไรก็ตามltraceแสดงการเรียกไลบรารีทั้งหมดที่ถูกเรียกใช้ในปฏิบัติการหรือกระบวนการที่กำลังทำงานอยู่ ชื่อของมันมาจากการติดตามการโทรเข้าห้องสมุด ตัวอย่างเช่น:

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

แหล่ง


1

ฉันคิดว่าคุณสามารถลองนี้ดีบักทุบตี: http://bashdb.sourceforge.net/


มีรายละเอียดจำนวนมากเกี่ยวกับการบันทึกเชลล์สคริปต์ผ่าน varaibles เชลล์ทั่วโลก เราสามารถเลียนแบบการเข้าสู่ระบบในเชลล์สคริปต์ชนิดที่คล้ายกัน: cubicrace.com/2016/03/efficient-logging-mechnism-in-shell.html
Piyush Chordia

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)

ทีละขั้นตอนเวลาดำเนินการ

ดูคำตอบของฉันเกี่ยวกับวิธีโปรไฟล์สคริปต์ทุบตี


0

มีรายละเอียดจำนวนมากเกี่ยวกับการบันทึกเชลล์สคริปต์ผ่าน varaibles เชลล์ทั่วโลก เราสามารถเลียนแบบการล็อกอินในเชลล์สคริปต์ชนิดเดียวกันได้: 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.