จะออกจากเชลล์สคริปต์ได้อย่างไรหากส่วนหนึ่งล้มเหลว?


51

ฉันจะเขียนเชลล์สคริปต์ที่ออกได้อย่างไรหากส่วนหนึ่งล้มเหลว? ตัวอย่างเช่นหากข้อมูลโค้ดต่อไปนี้ล้มเหลวสคริปต์ควรออก

n=0
until [ $n -ge 5 ]
do
  gksu *command* && break
  n=$[$n+1]
  sleep 3

คำตอบ:


88

วิธีหนึ่งที่จะเพิ่มset -eไปยังจุดเริ่มต้นของสคริปต์ของคุณ นั่นหมายถึง (จากhelp set):

  -e  Exit immediately if a command exits with a non-zero status.

ดังนั้นหากคำสั่งใด ๆ ของคุณล้มเหลวสคริปต์จะจบการทำงาน

หรือคุณสามารถเพิ่มexitข้อความชี้แจงที่จุดล้มเหลวที่เป็นไปได้:

command || exit 1

5
ฉัน (และวิกิพีเดียทุบตี ) ขอคนที่ค่อนข้างใส่ความคิดบางอย่างในข้อผิดพลาดที่เหมาะสมจัดการแทนที่จะใช้ (เสียจากการออกแบบ IMO) set -eคุณลักษณะ มันใช้ไม่ได้จริงที่นี่ OP ต้องการออกจากสคริปต์หลังจาก 5 ความพยายามที่ล้มเหลวในการเรียกใช้คำสั่ง
Stéphane Chazelas

1
@ StéphaneChazelasฉันจะไม่เถียงกับคุณเกี่ยวกับว่ามันพังฉันแน่ใจว่าคุณพูดถูก อย่างไรก็ตาม OP ถามว่า "ฉันจะเขียนเชลล์สคริปต์ที่ออกได้อย่างไรถ้าส่วนใดส่วนหนึ่งล้มเหลว" สิ่งใดที่ทำให้คุณคิดว่ามันเกี่ยวกับการออกจากหลังจากความล้มเหลว 5 ครั้ง?
terdon

เพราะฉันไม่สามารถคิดวิธีอื่นที่สามารถตีความคำถามได้
Stéphane Chazelas

1
@ StéphaneChazelasคุณอาจพูดถูก ฉันตีความมันอย่างแท้จริง: สคริปต์ทั้งหมดจะจบลงได้อย่างไร และset -eเป็นวิธีเดียวที่ฉันรู้ที่จะทำ
terdon

ใน snipet สคริปต์ที่คำสั่งที่อาจทำให้set -eเป็นsleep( breakเป็น builtin พิเศษจะทำให้เกิดสคริปต์เพื่อออกจากความล้มเหลวในเปลือกหอยมากที่สุดคำสั่งในifหรือด้านซ้ายของ&&ยังไม่ได้รับผลกระทบจากset -e, n=...อาจล้มเหลวถ้าnเป็นแบบอ่านอย่างเดียว แต่แล้ว ที่จะออกจากสคริปต์โดยไม่ใช้set -e) ดังนั้นการตีความจึงฟังดูไม่น่าจะเป็นไปได้ ฉันเห็นด้วยกับคำถามที่พูดไม่ดี
Stéphane Chazelas

17

คุณสามารถออกจากสคริปต์ได้ทุกที่โดยใช้คำexitสำคัญ นอกจากนี้คุณยังสามารถระบุรหัสออกเพื่อบ่งบอกถึงโปรแกรมอื่น ๆ ที่หรือวิธีการที่สคริปต์ของคุณล้มเหลวเช่นexit 1หรือexit 2อื่น ๆ (โดยการประชุมรหัสออก 0 สำหรับความสำเร็จและสิ่งที่มากกว่า 0 หมายถึงความล้มเหลวอย่างไรก็ตามโดยการประชุมออก รหัสข้างต้น 127 สงวนไว้สำหรับการยุติที่ผิดปกติ (เช่นโดยสัญญาณ)

การก่อสร้างทั่วไปเพื่อออกจากความล้มเหลวคือ

if [ failure condition ]; then
    exit n
fi

ที่มีความเหมาะสมและfailure condition nแต่ในบางสถานการณ์คุณอาจดำเนินการแตกต่างกัน ทีนี้สำหรับกรณีของคุณฉันตีความคำถามของคุณว่าหากการเรียกร้องข้อใดข้อหนึ่งในห้าข้อgksuล้มเหลวคุณจะต้องออก วิธีหนึ่งคือการใช้ฟังก์ชั่นเช่นนี้

function try_command {
    for i in 1 2 3 4 5 ; do
        if gksu command ; then
            return 0
        fi
    fi
    exit 1
}

try_commandแล้วเรียกห่วงโดย

มีวิธีการตอบคำถามของคุณขั้นสูงหรือซับซ้อน อย่างไรก็ตามวิธีการแก้ปัญหาข้างต้นนั้นเข้าถึงได้ง่ายสำหรับผู้เริ่มต้นมากกว่าพูดว่าโซลูชันของ Stephane


10
attempt=0
until gksu command; do
  attempt=$((attempt + 1))
  if [ "$attempt" -gt 5 ]; then
    exit 1
  fi
done

exitออกจากสคริปต์ยกเว้นว่ามันจะถูกเรียกใน subshell หากส่วนหนึ่งของสคริปต์นั้นอยู่ใน subshell เช่นเนื่องจากอยู่ใน(...)หรือ$(...)หรือเป็นส่วนหนึ่งของไปป์ไลน์แล้วมันจะออกจากsubshellนั้นเท่านั้น

ในกรณีดังกล่าวหากคุณต้องการให้สคริปต์ออกจากส่วนย่อยคุณจะต้องเรียกexitใช้ส่วนย่อยนั้นออก

ตัวอย่างเช่นที่นี่มี 2 ระดับย่อยของ subshells:

(
  life=hard
  output=$(
    echo blah
    [ "$life" = easy ] || exit 1 # exit subshell
    echo blih not run
  ) || exit # if the subshell exits with a non-zero exit status,
            # exit as well with the same exit status

  echo not run either
) || exit # if the subshell exits with a non-zero exit status,
          # exit as well with the same exit status

มันอาจกลายเป็นเรื่องยากหาก subshell เป็นส่วนหนึ่งของไปป์ไลน์ bashมี$PIPESTATUSอาเรย์พิเศษคล้ายกับzshของ$pipestatusที่สามารถช่วยคุณได้ที่นี่:

{
   echo foo
   exit 1
   echo bar
} | wc -c
subshell_ret=${PIPESTATUS[0]}
if [ "$subshell_ret" -ne 0 ]; then
  exit "$subshell_ret"
fi

3

กับดักจะดำเนินการเมื่อได้รับสัญญาณ

trap "echo EXIT;  exit" 0
trap "echo HUP;   exit" 1
trap "echo CTL-C; exit" 2
trap "echo QUIT;  exit" 3
trap "echo ERR;   exit" ERR
n=0
until [ $n -ge 5 ]
do
  n=$[$n+1]
  echo $n
  sleep 3
done

เรียกใช้สิ่งนี้และปล่อยให้มันออกตามปกติ วางกับสัญญาณ 0

EXIT

เรียกใช้อีกครั้งและขัดจังหวะด้วย ^ C มันดักทั้งสัญญาณ 2 และสัญญาณ 0

CTL-C
EXIT

สถานะการออกที่ไม่เป็นศูนย์จะดักบน ERR

ERR
EXIT
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.