วิธีปฏิบัติที่ดีที่สุดในการใช้ $? ในทุบตี?


10

เมื่อฉันอ่านคำตอบนี้เกี่ยวกับ $? คำถามอื่นอยู่ในใจ

มีวิธีปฏิบัติที่ดีที่สุดสำหรับวิธีใช้ $ หรือไม่ ในทุบตี?


ลองมาตัวอย่าง:

เรามีสคริปต์แบบเส้นตรงและฉันต้องการทราบว่าคำสั่งทั้งหมดจะทำงานได้ดี คุณคิดว่าเป็นการดีไหมที่จะเรียกใช้ฟังก์ชั่นเล็ก ๆ (ลองเรียกมันว่า "did_it_work") เพื่อตรวจสอบรหัสข้อผิดพลาดและแตกถ้าไม่ได้

#!/bin/bash 

function did_it_work {
    code=$1
    if [ "$code" -ne "0" ]
    then
        echo "Error failure: code $code "
        exit 1
    fi
}

dir=some/path

mkdir -p $dir
did_it_work $? 

cd $dir
did_it_work $? 

run_some_command
did_it_work $? 

แน่นอนว่าวิธีการนี้หมายความว่าฉันต้องแก้ไขปัญหาด้วยตนเองหากมีและเรียกใช้สคริปต์อีกครั้ง

คุณคิดว่านี่เป็นความคิดที่ดีหรือมีแนวปฏิบัติที่เหมาะสมอื่น ๆ

/ ขอบคุณ

คำตอบ:


15

วิธีหนึ่งที่พบบ่อยคือ:

die() {
    IFS=' ' # make sure "$*" is joined with spaces

    # output the arguments if any on stderr:
    [ "$#" -eq 0 ] || printf '%s\n' "$*" 1>&2
    exit 1
}

จากนั้นคุณใช้มันเช่นนี้:

mkdir -p some/path || die "mkdir failed with status $?"

หรือถ้าคุณต้องการให้มันรวมสถานะการออกคุณสามารถเปลี่ยนเป็น:

die() {
    last_exit_status=$?
    IFS=' '
    printf '%s\n' "FATAL ERROR: $* (status $last_exit_status)" 1>&2
    exit 1
}

แล้วใช้มันง่ายกว่า:

mkdir -p some/path || die "mkdir failed"

เมื่อล้มเหลวmkdirอาจมีข้อความแจ้งข้อผิดพลาดอยู่แล้วดังนั้นข้อความที่สองอาจซ้ำซ้อนและคุณสามารถทำได้:

mkdir -p some/path || exit   # with the same (failing) exit status as mkdir's
mkdir -p some/path || exit 1 # with exit status 1 always

(หรือใช้ตัวแปรแรกdieด้านบนโดยไม่มีอาร์กิวเมนต์)

ในกรณีที่คุณไม่เคยเห็นcommand1 || command2มาก่อนมันจะทำงานcommand1และถ้าล้มเหลวก็วิ่งcommand1command2

ดังนั้นคุณสามารถอ่านได้เช่น "ทำไดเรกทอรีหรือตาย"

ตัวอย่างของคุณจะมีลักษณะดังนี้:

mkdir -p some/path || die "mkdir failed"
cd some/path || die "cd failed"
some_command || die "some_command failed"

หรือคุณสามารถจัดตำแหน่งdiesเพิ่มเติมทางด้านขวาเพื่อให้รหัสหลักชัดเจนยิ่งขึ้น

mkdir -p some/path         || die "mkdir failed"
cd some/path               || die "cd failed"
some_command               || die "some_command failed"

หรือบนบรรทัดต่อไปนี้เมื่อบรรทัดคำสั่งยาว:

mkdir -p some/path ||
  die "mkdir failed"

cd some/path ||
  die "cd failed"

some_command ||
  die "some_command failed"

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

dir=some/path
mkdir -p -- "$dir"         || die "Cannot make $dir"
cd -P -- "$dir"            || die "Cannot cd to $dir"
some_command               || die "Cannot run some_command"

9

คุณสามารถเขียนรหัสของคุณใหม่ได้ดังนี้:

#!/bin/bash
function try {
    "$@"
    code=$?
    if [ $code -ne 0 ]
    then
        echo "$1 did not work: exit status $code"
        exit 1
    fi
}

try mkdir -p some/path
try cd some/path
try run_some_command

หากคุณไม่จำเป็นต้องบันทึกรหัสข้อผิดพลาด แต่เพียงว่าคำสั่งทำสำเร็จหรือไม่คุณสามารถย่อให้สั้นลงtry()ได้เช่น:

function try {
    if ! "$@"
    then
        echo "$1 did not work"
        exit 1
    fi
}

คุณยังสามารถใช้รหัสในรูปแบบนี้ <pre> ฟังก์ชันลอง {
BillThor

หากคุณใช้ฟังก์ชันนี้แบบอินไลน์และไม่ต้องการกลับจากด้านจริงคุณสามารถแทนที่return $?ด้วย:builtin
BillThor

8

หากคุณต้องการที่จะexitเกิดข้อผิดพลาดและใช้ Bash คุณควรพิจารณาset -eด้วย จากhelp set:

-e Exit ทันทีหากคำสั่งออกจากสถานะไม่เป็นศูนย์

หลักสูตรนี้ไม่ได้ให้ความยืดหยุ่นกับฟังก์ชั่น did_it_work () ของคุณ แต่เป็นวิธีที่ง่ายเพื่อให้แน่ใจว่าสคริปต์ทุบตีของคุณหยุดข้อผิดพลาดโดยไม่ต้องเพิ่มการเรียกไปยังฟังก์ชันใหม่ของคุณจำนวนมาก


set -eมีประโยชน์ มีบางคำสั่งที่ส่งคืนค่าที่ไม่เป็นศูนย์ภายใต้สถานการณ์ปกติ (ตัวอย่างเช่นdiff) command || trueเมื่อฉันใช้ชุดอีในบทที่ฉันคาดหวังผลตอบแทนที่ไม่ใช่ศูนย์ที่ฉันทำ
Shawn J. Goff

2
นอกจากนี้แม้ว่าคุณจะใช้set -eคุณสามารถตั้งค่าเป็น“การจัดการข้อยกเว้น” trap did_it_work EXITเพื่อจับข้อผิดพลาดทั้งหมดที่มี
Gilles 'หยุดความชั่วร้าย'

1
นี่เป็นส่วนหนึ่งของ POSIX ไม่ใช่คุณลักษณะเฉพาะของ bash ใช้ แต่ระวังข้อผิดพลาดบางอย่างmywiki.wooledge.org/BashFAQ/105
kmkaplan

@ ShawnJ.Goff command && trueฉันชอบที่จะทำ เช่นเดียวกับค่าที่ส่งคืนจะไม่เปลี่ยนแปลง
kmkaplan

@kmkaplan ความคิดเห็นสุดท้ายของคุณไม่สมเหตุสมผลกับฉันเลย วัตถุประสงค์command || trueคือเพื่อป้องกันไม่ให้set -eออกจากสคริปต์หากcommandส่งคืนโค้ดออกที่ไม่ใช่ศูนย์ มันเปลี่ยนรหัสออกเพราะเราต้องการ มีเพียงสิ่งเดียวเท่านั้นที่command && trueถูกเรียกใช้true(ส่งคืนรหัสทางออกศูนย์) หากคำสั่ง `ประสบความสำเร็จ (ส่งกลับรหัสทางออกศูนย์) - มันเป็นตัวเลือกที่สมบูรณ์
tripleee
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.