การปฏิบัติที่ดีที่สุดในการแสดงค่าบูลีนในเชลล์สคริปต์คืออะไร


15

ฉันรู้ว่ามีค่าบูลีนในbashแต่ฉันไม่เคยเห็นพวกเขาใช้ที่ใดก็ได้

ฉันต้องการเขียน wrapper สำหรับข้อมูลบางอย่างที่ค้นหาบนเครื่องของฉันเช่นมีการเสียบ / ติดตั้งไดรฟ์ USB นี้หรือไม่

อะไรคือวิธีปฏิบัติที่ดีที่สุดในการบรรลุเป้าหมาย

  • สตริง?

    drive_xyz_available=true
  • ตัวเลข (0 สำหรับจริง, ≠ 0 สำหรับเท็จ)?

    drive_xyz_available=0    # evaluates to true
  • ฟังก์ชั่น?

    drive_xyz_available() { 
        if available_magic; then 
                return 0 
        else 
                return 1 
        fi
    }

ฉันส่วนใหญ่สงสัยเกี่ยวกับสิ่งที่คาดหวังโดยคนอื่นที่ต้องการใช้เสื้อคลุม พวกเขาจะคาดหวังว่าค่าบูลีนคำสั่งเช่นตัวแปรหรือฟังก์ชั่นที่จะเรียก?

จากมุมมองด้านความปลอดภัยฉันคิดว่าตัวเลือกที่สองนั้นปลอดภัยที่สุด แต่ฉันชอบที่จะได้ยินประสบการณ์ของคุณ


3
help true ; help false ; help exit
Costas

3
@Costas คุณจะอธิบายอย่างละเอียดไหม?
Minix

คำตอบ:


2
bool(){ return "$((!${#1}))"; }

if bool "$var"
then : do true
else : do false

เพียงตั้งค่าตัวแปรเป็นอะไรก็ได้ แต่ไม่ใช่ค่าว่างสำหรับการทำงานด้านบน แต่[ -n "$var" ]จะสั้นลงหากไม่ชัดเจน

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

ด้านบนส่งคืน!notค่าบูลีนของ len อาร์กิวเมนต์แรกของมัน - ถ้าอาร์กิวเมนต์มีจำนวนอักขระใด ๆ ที่ไม่ใช่ 0 จะส่งคืน 0 หากไม่มีอักขระเลยก็จะคืนค่า 1 นี่คือการทดสอบเดียวกับที่คุณสามารถทำได้[ -n "$var" ]โดยทั่วไป bool()แต่มันก็ตัดมันในการทำงานน้อยชื่อ

นี่คือวิธีการทำงานของตัวแปรแฟล็ก ตัวอย่างเช่น:

[ -d "$dir" ] || dir=

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

for set in yes ''
do echo "${set:-unset or null}"
done

... ซึ่งจะพิมพ์ ...

yes
unset or null

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

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


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

@Minix ดีกว่าไหม
mikeserv

โดยทั่วไปฉันกำหนดtrueหรือfalseตัวแปรคุณสามารถทำได้if $variable; then ...
wurtel

@wurtel - ที่ต้องอาศัยค่าเริ่มต้น$IFS- และหากค่าของ var อาจมีการป้อนข้อมูลของผู้ใช้ทุกชนิดก็ให้โชคดี หากไม่ทราบค่าเริ่มต้นก็ไม่จำเป็นต้องทดสอบค่า ปลอดภัยยิ่งขึ้นคุณสามารถทำได้if ${var:+":"} false; thenเมื่อทำงานโดยไม่มีค่าบูลีนเป็นโมฆะ แต่นั่นไม่ค่อยมีประโยชน์มากกว่า[ -n "$var" ] &&
mikeserv

ถ้าฉันเริ่มต้นสคริปต์ด้วยvariable=falseแล้วตั้งค่าเป็นจริงตามเงื่อนไขใด ๆ (เช่นเดียวกับที่ฉันต้องการเมื่อใช้ตัวแปรใน C) จากนั้นก็ไม่มีปัญหาใด ๆ สิ่งที่คุณหลงใหลกับค่า IFS ที่แตกต่างกันและค่าตัวแปรสุ่มเป็นต้น .. .
wurtel

4

ในbashทุกตัวแปรนั้นเป็นสตริง (หรืออาร์เรย์หรือฟังก์ชั่น แต่มาพูดถึงตัวแปรปกติที่นี่)

เงื่อนไขถูกแยกวิเคราะห์ตามค่าส่งคืนของคำสั่งทดสอบ - ค่าส่งคืนไม่ใช่ตัวแปรเป็นสถานะออก เมื่อคุณประเมินif [ ... ]หรือif [[ ]]หรือif grep somethingหรืออะไรทำนองนั้นค่าส่งคืน 0 (ไม่ใช่สตริง 0 แต่ออกจากสถานะ 0 = สำเร็จ) หมายถึงจริงและส่วนที่เหลือหมายถึงเท็จ (ดังนั้นตรงกันข้ามกับสิ่งที่คุณคุ้นเคยกับในภาษาโปรแกรมที่คอมไพล์แล้ว แต่เนื่องจากมีวิธีหนึ่งที่จะประสบความสำเร็จและหลายวิธีที่จะล้มเหลวและผลลัพธ์ที่คาดหวังจากการดำเนินการมักจะสำเร็จ 0 จึงถูกใช้เป็นผลลัพธ์เริ่มต้นทั่วไปหากไม่มีสิ่งใดผิดพลาด) สิ่งนี้มีประโยชน์มากเพราะสามารถใช้ไบนารี่ใดก็ได้เป็นแบบทดสอบ - ถ้ามันล้มเหลวมันเป็นเท็จมิฉะนั้นก็เป็นจริง

trueและfalseโปรแกรม (มักถูกแทนที่ด้วย builtins) เป็นเพียงโปรแกรมเล็ก ๆ ที่ไม่ทำอะไรเลย - ไม่trueประสบความสำเร็จในการทำอะไรเลยและจบด้วย 0 ในขณะที่falseพยายามทำอะไรและ "ล้มเหลว" ออกด้วย 1 ฟังดูไม่มีประโยชน์

สำหรับวิธีการส่งผ่านความจริงโดยรอบมันขึ้นอยู่กับคุณ เป็นเรื่องปกติที่จะใช้ "y" หรือ "ใช่" เพื่อความจริงและการใช้งานif [ x"$variable" = x"yes" ](ต่อท้ายสตริงดัมมี่xเพราะหาก$variableเกิดขึ้นจะมีความยาวเป็นศูนย์สิ่งนี้จะป้องกันการสร้างคำสั่งปลอมif [ = "yes" ]ที่ไม่แยกวิเคราะห์) นอกจากนี้ยังอาจเป็นประโยชน์ในการใช้สตริงว่างเปล่าเป็นเท็จและใช้[ -z "$variable ]เพื่อทดสอบว่ามันมีความยาวเป็นศูนย์หรือไม่หรือ-nไม่ใช่ศูนย์

อย่างไรก็ตามมันค่อนข้างยากที่จะต้องผ่านค่าบูลีนในbash- มันเป็นเรื่องธรรมดามากที่จะเกิดexitความล้มเหลวหรือส่งคืนผลลัพธ์ที่เป็นประโยชน์ (หรือเป็นศูนย์ถ้ามีอะไรผิดพลาดและทดสอบสตริงว่าง) และกรณีส่วนใหญ่สามารถ ทดสอบความล้มเหลวโดยตรงจาก statatus ทางออก


ในกรณีของคุณคุณต้องการฟังก์ชั่นที่จะทำหน้าที่เป็นคำสั่งอื่น ๆ (ดังนั้นกลับ 0 เมื่อประสบความสำเร็จ) ดังนั้นตัวเลือกสุดท้ายของคุณดูเหมือนจะเป็นทางเลือกที่ถูกต้อง

นอกจากนี้คุณอาจไม่จำเป็นต้องมีreturnคำสั่ง หากฟังก์ชั่นนั้นง่ายเพียงพอคุณสามารถใช้ความจริงที่ว่ามันคืนค่าสถานะของคำสั่งที่ดำเนินการครั้งสุดท้ายในฟังก์ชั่น ดังนั้นฟังก์ชั่นของคุณก็เป็นได้

drive_xyz_available() {
   [ -e /dev/disk/by-uuid/whatever ]
}

หากคุณกำลังทดสอบว่ามีโหนดอุปกรณ์อยู่ (หรือ grep /proc/mountsเพื่อตรวจสอบว่ามีการติดตั้งอยู่หรือไม่)


นั่นเป็นบทสรุปที่ดีมากขอบคุณที่สละเวลาเขียนมัน ฉันสามารถอนุมานจากย่อหน้าสุดท้ายของคุณว่าคุณจะพิจารณาว่าตัวเลือกนั้นdrive_xyz_available()เป็นเรื่องธรรมดาที่สุดหรือไม่?
Minix

คุณสามารถให้ตัวอย่างสำหรับy = trueกรณีทั่วไปได้หรือไม่ จากประสบการณ์ของฉันสคริปต์ wrapper ส่วนใหญ่ทดสอบค่าที่ไม่เป็นโมฆะใด ๆ เพื่อพิจารณาว่าเป็นจริง - อย่างน้อยที่ตัวแปรสภาพแวดล้อมที่ตีความเกี่ยวข้อง ไม่เช่นนั้นพวกเขาจะไม่สนใจรถยนต์เชลล์เลย
mikeserv

3
ifไม่จำเป็นต้องใช้สตริงจำลองสำหรับการทดสอบหากมีการอ้างถึงตัวแปร if [ "$variable" = "yes" ]ทำงานได้ดีแม้ว่าจะไม่ได้ตั้งค่าตัวแปร $
daniel kullmann

-2

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

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

ดังนั้นฉันจะใช้วิธีการนั้นสำหรับจริง / เท็จ if (( ! $? ));then OK;else NOOK;fi


ฉันจะเขียนหนึ่งสำหรับตัวเลือกสุดท้ายแล้ว ขอขอบคุณ.
Minix

5
หมายเลขที่ไม่ใช่ศูนย์เป็นเท็จจริงและศูนย์เป็นจริง ดูเพียงแค่ในการส่งออกของและtrue; echo $? false; echo $?
Ruslan

@Ruslan คุณตรวจสอบผลลัพธ์ของคำสั่งของฉันหรือไม่? ฉันเดาว่าคุณไม่ทำไม่งั้นคุณคงไม่ได้ระบุว่าคุณทำอะไร 0 เป็นเท็จหมายเลขอื่นใดเป็นจริงเหตุผลที่ทำให้!ผลลัพธ์ไม่เป็นจริง ผลลัพธ์จากคำสั่งคือ 0 เมื่อเสร็จสิ้นอย่างถูกต้องซึ่งไม่ได้หมายความว่า 0 เป็นจริง คำtrueนั้นอาจเป็น 0 แต่ 0 ไม่เป็นความจริงเนื่องจากifเงื่อนไขแสดงให้เห็น
YoMismo

นั่นเป็นเช่นเดียวกับที่บอกว่าใน C / C ++ 0เป็นtrueเพราะif(!x){True();}else{False();}จะเรียกเมื่อTrue() x==0แต่การตรวจสอบที่ถูกต้องจะไม่ได้แต่!x !!x
Ruslan

คุณผิด waaaaaaayay ฉันไม่ได้พูดเกี่ยวกับสิ่งที่และสิ่งที่สั่งซื้อมีสิ่งที่คุณเขียนหลังจากifฉันเพียงแค่ระบุความจริงที่ว่าที่นี่ (ในทุบตีหรือ ksh หรือ tsh หรือ .... ) เช่นใน C / C ++ a 0 เป็นเท็จใด ๆ หมายเลขอื่น ๆ ที่เป็นความจริงตามที่คุณสามารถอ่านในการเชื่อมโยงที่ตาม implementatins เริ่มต้นของ C ไม่ให้ชนิดบูลีนถูกกำหนดให้เป็น ints ที่ 0 เป็นเท็จและ TRUE 1 en.wikipedia.org/wiki/Boolean_data_type
YoMismo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.