วิธีหยุดสคริปต์ bash เมื่อเงื่อนไขล้มเหลว


11

ที่นี่มันแสดงให้เห็นถึงการใช้||และ&&ในบรรทัดเดียวเพื่อเชื่อมต่อการดำเนินการคำสั่ง: ฉันจะตรวจสอบข้อผิดพลาด apt-get ในสคริปต์ทุบตีได้อย่างไร

ฉันกำลังพยายามหยุดการประมวลผลสคริปต์หากเงื่อนไขบางอย่างล้มเหลว

เช่น

false || echo "Obvious error because its false on left" && exit

ที่นี่มันพิมพ์Obvious error because its false on the leftและออกจากคอนโซลซึ่งเป็นสิ่งที่ฉันต้องการ

true || echo "This shouldn't print" && exit

ที่นี่ไม่มีการพิมพ์เสียงสะท้อน แต่exitคำสั่งทำงานได้ดีเช่นคอนโซลถูกปิดไม่ควรexitคำสั่งไม่ทำงานเพราะคำสั่ง echo ทางด้านขวาไม่ได้ถูกดำเนินการ หรือโดยค่าเริ่มต้นข้อความที่ถือว่าเป็นเท็จทางด้านซ้ายของ&&ผู้ประกอบการ?

แก้ไข: ฉันควรได้กล่าวถึงก่อนหน้านี้เป้าหมายของฉันคือการสะท้อนข้อผิดพลาดและออกหากไม่ชัดเจน wrt กรณีเฉพาะของฉันในการจับข้อผิดพลาดเมื่อจัดกลุ่มเงื่อนไขโดยใช้ && และ | |, @ bodhi.zazen คำตอบจะช่วยแก้ปัญหา

@takatakatek คำตอบทำให้ชัดเจนมากขึ้นเกี่ยวกับการควบคุมการไหลและลิงค์คู่มือทุบตีเป็นเลิศ

@muru ตอบมีคำอธิบายที่ดีว่าทำไมไม่ใช้ set -e ถ้าคุณต้องการให้ข้อความแสดงความผิดพลาดแบบกำหนดเองถูกเลือกด้วยการใช้ perl และ trap ซึ่งฉันคิดว่าเป็นวิธีที่มีประสิทธิภาพมากขึ้น


เท่าที่ฉันสามารถบอกได้ว่ามันจบลงแล้วเมื่อสคริปต์เสร็จสิ้น
Panther

คำตอบ:


10

คุณอาจต้องการ (ตามที่ระบุโดยผู้ขับรถเหล็ก)

true || { echo "This shouldn't print" && exit; }

มิฉะนั้นสคริปต์ของคุณจะอ่านหนึ่งเงื่อนไขในเวลา

a หรือ b แล้วออก

ฉันคิดว่าคุณต้องการหรือ (b และออก)?


4
ที่จริงแล้วคุณต้องใช้{ ... ; }(ตามที่ @steeldriver แนะนำ) มิฉะนั้นexitจะออกจากเชลล์ย่อยเท่านั้นและพาเรนต์เชลล์จะดำเนินการสคริปต์ต่อไป
Gordon Davisson

14

ปัญหาคือ || และ && เพียงข้ามหนึ่ง stanza ที่ตามมาของเชนคำสั่งเมื่อเงื่อนไขล้มเหลว ถ้าคุณเขียนโครงสร้างบล็อกเต็มมันเหมาะสม สิ่งที่คุณเขียนจะกลายเป็นสิ่งนี้:

if ! true ; then
   echo "This shouldn't print"
else
   exit
fi

สิ่งที่คุณต้องการคือ:

if ! true ; then
   echo "This shouldn't print"
   exit
fi

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


2
ใช่ในความคิดของฉันนี้เป็นอีกวิธีที่ควรจะเขียนในทุบตี
DerHugo

@takatakatek สิ่งนี้ทำให้ชัดเจนมากขึ้นว่าทำไมมันล้มเหลวในกรณีของฉัน ฉันเห็นด้วยว่าเหตุผลนี้ชัดเจนในเหตุผลนี้ แต่ไม่ใช่เหตุผลสำหรับการจัดกลุ่มเงื่อนไขที่ใช้ && และ || คือการหลีกเลี่ยงการแสดงโดยใช้คำสั่งแบบมีเงื่อนไข?
kosol

@kosol ใช่ && และ || รวมสองสิ่ง: การทดสอบสถานะการออกของคำสั่งก่อนหน้าและระบุคำสั่งเดียว (หรือกลุ่มคำสั่ง) ที่จะดำเนินการ (สำหรับ &&) หรือข้าม (สำหรับ ||) มันมีประโยชน์สำหรับกรณีง่าย ๆ แต่ไม่สามารถแทนที่if ... then ... elif ... else ... fiบล็อกที่แสดงได้อย่างสมบูรณ์ ฉันสงสัยว่าคุณอาจไม่ทราบว่า Bash ไม่มีประเภทบูลีนจริงในภาษาที่ซับซ้อนกว่า ถ้าออกจากสถานะของคำสั่งเป็น0 (ศูนย์), ทุบตีขนมที่เป็นจริง / ความสำเร็จ ถ้าสถานะทางออกที่ไม่ใช่ศูนย์ถือว่าทุบตีที่เป็นเท็จ / ความล้มเหลว
takatakatek

7

วิธีที่ง่ายที่สุดที่จะล้มเหลวในข้อผิดพลาดคือการใช้-eตัวเลือกของ bash ( set -eหรือ/bin/bash -eใน shebang) อย่างไรก็ตามสิ่งนี้ไม่ได้ทำให้ง่ายต่อการส่งข้อความแสดงข้อผิดพลาดที่กำหนดเอง มีสำนวนสองสามอย่างที่ทำให้ง่ายขึ้น:

die à la Perl

Perl มีdieคำสั่งที่สะดวกมากซึ่งพิมพ์ข้อความไปยัง stderr และทำให้เกิดข้อยกเว้นซึ่งมักจะนำไปสู่การยกเลิกสคริปต์ คุณสามารถเลียนแบบสิ่งนี้:

die () {
  ret=$?
  print "%s\n" "$@" >&2
  exit "$ret"
}

false || die "Obvious error because its false on left"
true || die "This shouldn't print"

trap ERR

trap <command>คำสั่งสามารถใช้ในการเรียกใช้คำสั่งเมื่อได้รับสัญญาณหรือเมื่อออกจากสคริปต์ ( trap ... EXIT) หรือเมื่อคำสั่งกลับข้อผิดพลาด ( trap ... ERR) ดังนั้นสิ่งที่ชอบ:

trap 'ret=$?; printf "%s\n" "$ERR_MSG" >&2; exit "$ret"' ERR

แล้ว:

ERR_MSG="Obvious error because its false here"
false
ERR_MSG="This shouldn't print"
true

ในทั้งสองกรณีนี้ผมขอแนะนำให้ใช้อย่างน้อยexit 1เพื่อระบุว่าสคริปต์ที่ล้มเหลว ธรรมดาexitจะใช้สถานะออกของคำสั่งก่อนหน้าซึ่งในกรณีนี้จะเป็นคำสั่งechoหรือprintfซึ่งมักจะประสบความสำเร็จ การบันทึกสถานะการออกของคำสั่งที่ล้มเหลวอย่างที่ฉันทำไว้ที่นี่น่าจะดี


6

คุณสามารถลองทดลองใช้เล็กน้อยด้วยการเริ่มต้นสคริปต์ด้วย

#!/bin/bash -e

-e ทำให้แน่ใจว่าสคริปต์ออกจากช่วงเวลาที่บางสิ่งกลับมาเป็นเท็จ จากนั้นสามารถหลีกเลี่ยงความล้มเหลวที่เฉพาะเจาะจงได้something || true

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