วิธีตรวจสอบว่าคำสั่งสำเร็จหรือไม่


234

มีวิธีใดที่จะตรวจสอบว่ามีข้อผิดพลาดในการดำเนินการคำสั่งหรือไม่?

ตัวอย่าง:

test1=`sed -i "/:@/c connection.url=jdbc:oracle:thin:@$ip:1521:$dataBase" $search`
valid $test1

function valid () {
  if $test -eq 1; then
    echo "OK"
    else echo "ERROR" 
  fi
}

ฉันลองทำแล้ว แต่ดูเหมือนว่ามันไม่ทำงาน ฉันไม่ทำอย่างนั้น


9
ต้องการ$ (foo)มากกว่า backticks ` foo 'เพราะคุณสามารถทำมันได้และง่ายกว่าที่จะแยกแยะจาก apostrophes
ผู้ใช้ที่ไม่รู้จัก

1
BTW คุณจะต้องกำหนดฟังก์ชั่น ( valid) ก่อนที่จะเรียกมัน
wjandrea

คำตอบ:


344

$?ค่าตอบแทนจะถูกเก็บไว้ใน 0 หมายถึงความสำเร็จส่วนอื่น ๆ บ่งชี้ข้อผิดพลาด

some_command
if [ $? -eq 0 ]; then
    echo OK
else
    echo FAIL
fi

เช่นเดียวกับค่าที่เป็นข้อความอื่น ๆ คุณสามารถเก็บไว้ในตัวแปรสำหรับการเปรียบเทียบในอนาคต:

some_command
retval=$?
do_something $retval
if [ $retval -ne 0 ]; then
    echo "Return code was not zero but $retval"
fi

man testสำหรับผู้ประกอบการเปรียบเทียบเป็นไปได้ดู


เยี่ยมมาก ... ฉันจะระงับข้อผิดพลาดเอาต์พุตได้หรือไม่? !! , เพราะในกรณีนี้ฉันมีข้อผิดพลาด 2 ข้อ: คำสั่งผิดพลาด "text" ex, ไม่พบไฟล์และข้อผิดพลาดของฉัน "text" ซึ่งในกรณีนี้ล้มเหลวตัวอย่างเช่น
moata_u

@moata_u: คุณสามารถจัดเก็บค่าในตัวแปรตามที่แสดงในคำตอบของฉัน
Lekensteyn

@moata_u: คุณต้องใส่;ก่อนelseและfi: `ถ้า ... ; จากนั้น ... ; อื่น ... ; fi
Lekensteyn

4
นี่คือการใช้งานที่ไร้ประโยชน์ของ test
David Foerster

1
@Blauhirn [ $? ](หรือเทียบเท่าtest $?) ไม่ทำงานเนื่องจาก$?ประเมินเป็นตัวเลข (0, 1, ฯลฯ ) ซึ่งไม่เป็นโมฆะ ดูเอกสารสำหรับtest : "ถ้าไม่ระบุ EXPRESSION, 'test' จะส่งกลับค่า false ถ้า EXPRESSION เป็นอาร์กิวเมนต์ตัวเดียว 'test' จะส่งกลับค่า false ถ้าอาร์กิวเมนต์นั้นเป็นโมฆะและเป็นจริงมิฉะนั้น"
Lekensteyn

87

หากคุณต้องการทราบว่าคำสั่งสำเร็จหรือล้มเหลวอย่ารบกวนการทดสอบ$?เพียงทดสอบคำสั่งโดยตรง เช่น:

if some_command; then
    printf 'some_command succeeded\n'
else
    printf 'some_command failed\n'
fi

และการกำหนดเอาต์พุตให้กับตัวแปรจะไม่เปลี่ยนค่าส่งคืน (ดียกเว้นว่ามันจะทำงานแตกต่างกันเมื่อ stdout ไม่ใช่เทอร์มินัลแน่นอน)

if output=$(some_command); then
    printf 'some_command succeded, the output was «%s»\n' "$output"
fi

http://mywiki.wooledge.org/BashGuide/TestsAndConditionalsอธิบายifรายละเอียดเพิ่มเติม


ถ้าคุณต้องการทำสิ่งอื่นนอกเหนือจากการแตกแขนงเช่นการจัดเก็บบูลีนไม่ว่าจะล้มเหลวหรือไม่กลายเป็น. ini จากนั้นตัวแปรเอาต์พุตของคุณจะไม่ทำเช่นนั้น แต่$?ทำดังนั้นคุณไม่ถูกต้องที่จะบอกว่าการทดสอบคำสั่งนั้นดีกว่าโดยตรง
Timothy Swan

การกำหนดเอาท์พุทให้กับตัวแปรอาจเปลี่ยนค่าที่ส่งคืนเมื่อlocalคำสั่งหนึ่งใช้เช่นlocal foo=$(false); echo $?;สร้าง0บนเอาต์พุต แต่localมีความเกี่ยวข้องเฉพาะภายในฟังก์ชัน bash เท่านั้น
Cromax

26
command && echo OK || echo Failed

หากcommandส่งคืนข้อผิดพลาดบนหน้าจอจะซ่อนมันได้อย่างไร
Sigur

ถ้าcommandเขียนข้อผิดพลาดออกไป stderr command 2> /dev/null && echo OK || echo Failedคุณสามารถใช้แบบฟอร์ม 2> /dev/nullเปลี่ยนเส้นทาง stderr /dev/nullส่งออกไปยัง อย่างไรก็ตามยูทิลิตี้บางอย่างจะเขียนข้อผิดพลาดไปยัง stdout (แม้ว่าจะเป็นการปฏิบัติที่ไม่ดี) ในกรณีนี้คุณสามารถละเว้น 2 จากการเปลี่ยนเส้นทาง แต่คุณจะสูญเสียผลลัพธ์ใด ๆ จากคำสั่ง วิธีการตรวจสอบความสำเร็จนี้เป็นสิ่งที่ดีสำหรับตรรกะที่ประกอบไปด้วยระบบง่าย ๆ แต่สำหรับพฤติกรรมที่ซับซ้อนมากขึ้นดีที่สุดในการตรวจสอบ$?ความสำเร็จของคำสั่งหรือใช้ifวิธีการบล็อกที่ระบุไว้ในคำตอบของ @ geirha
Bender the Greatest

17

$? ควรมีสถานะทางออกของคำสั่งก่อนหน้าซึ่งควรเป็นศูนย์สำหรับไม่มีข้อผิดพลาด

ดังนั้นสิ่งที่ชอบ;

cd /nonexistant
if [ $? -ne 0 ]
then
    echo failed
else
    echo success!
fi

สำหรับกรณีส่วนใหญ่จะใช้การ && สร้างเพื่อคำสั่งลูกโซ่ที่ต้องพึ่งพาซึ่งกันและกัน ดังนั้นcd /nonexistant && echo success!จะไม่สะท้อนความสำเร็จเพราะคำสั่งหยุดก่อน && ข้อสรุปของเรื่องนี้คือ || ซึ่งcd /nonexistant || echo fail จะสะท้อนล้มเหลวเพราะซีดีล้มเหลว (สิ่งนี้จะมีประโยชน์หากคุณใช้บางอย่างเช่น || exit ซึ่งจะจบสคริปต์หากคำสั่งก่อนหน้านี้ล้มเหลว)


เยี่ยมมาก ... ฉันจะระงับข้อผิดพลาดเอาต์พุตได้หรือไม่? !! , เพราะในกรณีนี้ฉันมีข้อผิดพลาด 2 ข้อผิดพลาดคำสั่ง "ข้อความ" อดีตไม่พบไฟล์และข้อผิดพลาด "ข้อความ" ซึ่งในกรณีนี้ล้มเหลวตัวอย่างเช่น
moata_u


5
command && echo $? || echo $?

คุณหมายถึงcommand; echo $?อะไร
Javier Buzzi

ไม่บรรทัดของฉันถูกต้องมันให้รหัสผลลัพธ์ที่แท้จริงเป็นตัวเลขโดยไม่คำนึงว่าสำเร็จหรือล้มเหลว
modrobert

1
ตกลงโปรดอธิบายความแตกต่างของสิ่งเหล่านี้ให้ฉัน: true && echo $? || echo $?/ true; echo $?และfalse && echo $? || echo $?/ false; echo $?- คุณจะพบว่าพวกเขาทำสิ่งเดียวกัน: D
Javier Buzzi

ใช่ผลลัพธ์เดียวกัน แต่ไม่มีเงื่อนไข คำถามเดิมที่ถามคือ "วิธีตรวจสอบว่าคำสั่งสำเร็จหรือไม่" นี่เป็นไปตามคำตอบก่อนหน้า ฉันเดาตัวอย่างที่ดีกว่าน่าจะเป็น:command && echo "success: $?" || echo "fail: $?"
modrobert

5

ควรสังเกตว่าif...then...fiและ&&/ ||ประเภทของวิธีการจัดการกับสถานะทางออกที่ส่งคืนโดยคำสั่งที่เราต้องการทดสอบ (0 เมื่อสำเร็จ); อย่างไรก็ตามคำสั่งบางคำสั่งจะไม่ส่งคืนสถานะการออกที่ไม่ใช่ศูนย์หากคำสั่งล้มเหลวหรือไม่สามารถจัดการกับอินพุตได้ ซึ่งหมายความว่าปกติifและ&&/ ||แนวทางจะไม่ทำงานสำหรับคำสั่งเฉพาะเหล่านั้น

ตัวอย่างเช่นบน Linux GNU fileยังคงออกด้วย 0 หากได้รับไฟล์ที่ไม่มีอยู่เป็นอาร์กิวเมนต์และfindไม่สามารถระบุตำแหน่งผู้ใช้ไฟล์ที่ระบุ

$ find . -name "not_existing_file"                                          
$ echo $?
0
$ file ./not_existing_file                                                  
./not_existing_file: cannot open `./not_existing_file' (No such file or directory)
$ echo $?
0

ในกรณีเช่นนี้วิธีที่เป็นไปได้วิธีหนึ่งที่เราสามารถจัดการกับสถานการณ์ได้คือการอ่านstderr/ stdinข้อความเช่นที่ส่งคืนโดยfileคำสั่งหรือแยกวิเคราะห์เอาต์พุตของคำสั่งเช่นfindนี้ สำหรับวัตถุประสงค์นั้นcaseสามารถใช้ข้อความสั่งได้

$ file ./doesntexist  | while IFS= read -r output; do                                                                                                                  
> case "$output" in 
> *"No such file or directory"*) printf "%s\n" "This will show up if failed";;
> *) printf "%s\n" "This will show up if succeeded" ;;
> esac
> done
This will show up if failed

$ find . -name "doesn'texist" | if ! read IFS= out; then echo "File not found"; fi                                                                                     
File not found

(นี่คือ repost คำตอบของฉันเองสำหรับคำถามที่เกี่ยวข้องที่ unix.stackexchange.com )


1

ดังที่กล่าวไว้ในคำตอบอื่น ๆ การทดสอบ$?พินัยกรรมอย่างง่ายเช่นนี้

if [ $? -eq 0 ]; then something; fi

หากคุณต้องการทดสอบว่าคำสั่งล้มเหลวคุณสามารถใช้เวอร์ชันที่สั้นกว่าในbash(แต่อาจมากเกินไป) ดังนี้:

if (($?)); then something; fi

นี้ทำงานโดยใช้(( ))โหมดเลขคณิตดังนั้นหากคำสั่งกลับsuccessเช่น$? = 0นั้นการทดสอบประเมิน((0))ซึ่งการทดสอบเป็นอย่างอื่นก็จะกลับมาfalsetrue

เพื่อทดสอบความสำเร็จคุณสามารถใช้:

if ! (($?)); then something; fi

แต่มันก็สั้นกว่าตัวอย่างแรกไม่มากนัก


1
วิจารณ์ที่สร้างสรรค์?
afuna

0

สำหรับข้อผิดพลาดในการพิสูจน์คำสั่งของคุณ:

execute [INVOKING-FUNCTION] [COMMAND]

execute () {
    error=$($2 2>&1 >/dev/null)

    if [ $? -ne 0 ]; then
        echo "$1: $error"
        exit 1
    fi
}

แรงบันดาลใจในการผลิตแบบลีน:


-2

ถ้า [$ (คำสั่ง)]; echo "สำเร็จ" แล้ว; Fi


3
trueสำเร็จif [ $(true) ]; then echo "succeed"; fiแต่succeedไม่ได้พิมพ์ ในความเป็นจริงนี้ไม่เคยตรวจสอบว่าcommandประสบความสำเร็จ มันก็ควรจะใช้if commandในขณะที่การโพสต์ของ geirha $( )เป็นคำสั่งเปลี่ยนตัว [ ]เป็นนิพจน์เงื่อนไข การแยกคำและการขยายชื่อไฟล์ขาดหายไปซึ่งเป็นการทดสอบว่าcommandมีเอาต์พุตหรือไม่
Eliah Kagan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.