ทดสอบว่าตัวแปรถูกตั้งค่าเป็น bash หรือไม่เมื่อใช้“ set -o nounset”


100

รหัสต่อไปนี้ออกพร้อมกับข้อผิดพลาดตัวแปร unbound จะแก้ไขได้อย่างไรในขณะที่ยังใช้set -oตัวเลือก nounset อยู่

#!/bin/bash

set -o nounset

if [ ! -z ${WHATEVER} ];
 then echo "yo"
fi

echo "whatever"

คำตอบ:


101
#!/bin/bash

set -o nounset


VALUE=${WHATEVER:-}

if [ ! -z ${VALUE} ];
 then echo "yo"
fi

echo "whatever"

ในกรณีนี้VALUEจะกลายเป็นสตริงว่างหากWHATEVERไม่ได้ตั้งค่าไว้ เรากำลังใช้ส่วน{parameter:-word}ขยายซึ่งคุณสามารถค้นหาได้ในman bash"การขยายพารามิเตอร์"


15
เพียงแค่แทนที่ถ้า [! -z $ {VALUE}]; ด้วยถ้า [! -z $ {WHATEVER: -}];
Angelom

18
:-ตรวจสอบว่าตัวแปรไม่ได้ตั้งค่าหรือว่างเปล่า หากคุณต้องการที่จะตรวจสอบเฉพาะไม่ว่าจะเป็นไม่มีการตั้งค่าการใช้งาน:- VALUE=${WHATEVER-}นอกจากนี้วิธีตรวจสอบว่าตัวแปรว่างเปล่า:if [ "${WHATEVER+defined}" = defined ]; then echo defined; else echo undefined; fi
l0b0

1
นอกจากนี้จะใช้ไม่ได้หาก$WHATEVERมีเพียงช่องว่าง - ดูคำตอบของฉัน
l0b0

11
มีเหตุผลในการใช้ " ! -z" แทน just " -n" หรือไม่?
Jonathan Hartley

32

คุณต้องอ้างตัวแปรหากคุณต้องการได้ผลลัพธ์ที่คุณคาดหวัง:

check() {
    if [ -n "${WHATEVER-}" ]
    then
        echo 'not empty'
    elif [ "${WHATEVER+defined}" = defined ]
    then
        echo 'empty but defined'
    else
        echo 'unset'
    fi
}

ทดสอบ:

$ unset WHATEVER
$ check
unset
$ WHATEVER=
$ check
empty but defined
$ WHATEVER='   '
$ check
not empty

ฉันพยายามนี้และฉันประหลาดใจงานนี้ ... ทุกอย่างถูกต้องยกเว้นตาม"info bash", "${WHATEVER-}"ควรมี":"(ลำไส้ใหญ่) ก่อน"-"(เส้นประ) ที่ชอบ: "${WHATEVER:-}"และ"${WHATEVER+defined}"ควรจะมีลำไส้ใหญ่ก่อน"+"(บวก) "${WHATEVER:+defined}"เช่น: สำหรับฉันมันได้ผลทั้งสองวิธีโดยมีหรือไม่มีลำไส้ใหญ่ ในบางเวอร์ชันของ 'nix อาจใช้ไม่ได้หากไม่มีเครื่องหมายจุดคู่ดังนั้นจึงควรเพิ่มเข้าไป
Kevin Fegan

9
Nope, -, +, :+และ:-ได้รับการสนับสนุนทั้งหมด อดีตตรวจสอบว่าตัวแปรที่มีการตั้งค่าและหลังตรวจสอบไม่ว่าจะเป็นการตั้งค่าหรือเปล่า From man bash: "การละเว้นลำไส้ใหญ่จะส่งผลให้เกิดการทดสอบเฉพาะสำหรับพารามิเตอร์ที่ไม่ได้ตั้งค่า"
l0b0

1
ไม่เป็นไร =) คุณถูก. ฉันไม่รู้ว่าฉันพลาดไปได้อย่างไร
Kevin Fegan

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

11

แล้ว oneliner ล่ะ?

[ -z "${VAR:-}" ] && echo "VAR is not set or is empty" || echo "VAR is set to $VAR"

-z ตรวจสอบทั้งตัวแปรว่างหรือไม่ได้ตั้งค่า


2
ไม่-zตรวจสอบเฉพาะว่าพารามิเตอร์ถัดไปว่างเปล่า -zเป็นเพียงข้อโต้แย้งของ[คำสั่ง การขยายตัวแปรเกิดขึ้นก่อนที่[ -zจะทำอะไรได้
dolmen

1
ดูเหมือนจะเป็นวิธีแก้ปัญหาที่ถูกต้องเนื่องจากจะไม่สร้างข้อผิดพลาดหากไม่ได้ตั้งค่า $ VAR @dolmen คุณช่วยยกตัวอย่างได้ไหมว่าเมื่อใดที่มันไม่ได้ผล?
Chris Stryczynski

@dolmen ได้อ่านแหล่งข้อมูล bash ต่างๆเกี่ยวกับการขยายพารามิเตอร์และค้นหาคำตอบอื่น ๆ ที่ซับซ้อนมากเกินไปฉันไม่เห็นอะไรผิดปกติกับสิ่งนี้ ดังนั้น "การชี้แจง" ของคุณในขณะที่ถูกต้องในทางเทคนิคดูเหมือนจะไม่มีจุดหมายในทางปฏิบัติเว้นแต่คุณจะต้องแยกความแตกต่างระหว่าง unset กับว่างเปล่า ฉันทดสอบ unset ว่างเปล่าและไม่ว่างเปล่า (bash 4) และมันก็ทำตามที่โฆษณาทุกครั้ง
JL Peyret

10

สมมติฐาน:

$ echo $SHELL
/bin/bash
$ /bin/bash --version | head -1
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
$ set -o nounset

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

$ [[ "${HOME:?}" ]]

$ [[ "${IAMUNBOUND:?}" ]]
bash: IAMUNBOUND: parameter null or not set

$ IAMNULL=""
$ [[ "${IAMNULL:?}" ]]
bash: IAMNULL: parameter null or not set

หากคุณไม่ต้องการให้สคริปต์ออก:

$ [[ "${HOME:-}" ]] || echo "Parameter null or not set."

$ [[ "${IAMUNBOUND:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

$ IAMNULL=""
$ [[ "${IAMUNNULL:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

คุณยังสามารถใช้[และ]แทน[[และ]]สูงกว่าได้ แต่แบบหลังจะดีกว่าใน Bash

สังเกตสิ่งที่ลำไส้ใหญ่ทำข้างต้น จากเอกสาร :

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

เห็นได้ชัดว่าไม่มีความจำเป็นสำหรับ -n-zหรือ

โดยสรุปฉันมักจะใช้แค่[[ "${VAR:?}" ]]. ตามตัวอย่างนี้จะพิมพ์ข้อผิดพลาดและออกหากตัวแปรเป็นโมฆะหรือไม่ได้ตั้งค่า


4

คุณสามารถใช้ได้

if [[ ${WHATEVER:+$WHATEVER} ]]; then

แต่

if [[ "${WHATEVER:+isset}" == "isset" ]]; then

อาจจะอ่านได้มากขึ้น


การเปรียบเทียบสตริงควรใช้ตัวดำเนินการมาตรฐาน (POSIX) =ไม่ใช่==เพื่อช่วยในการพกพาและ[แทนที่จะใช้[[ถ้าเป็นไปได้
Jens

2
@Jens คำถามเฉพาะสำหรับการทุบตีและรวมถึงset -o nounsetการทุบตีโดยเฉพาะ หากคุณใส่ไว้#!/bin/bashที่ด้านบนสุดของสคริปต์ควรใช้การปรับปรุงของ bash
Bruno Bronosky

0

ขณะนี้ไม่ว่ากรณีการใช้งานถามข้างต้นผมได้พบว่าถ้าคุณต้องการที่จะใช้nounset(หรือ-u ) พฤติกรรมเริ่มต้นคือคนที่คุณต้องการที่จะออกจากการเป็นศูนย์ที่มีข้อความที่สื่อความหมาย

ฉันใช้เวลานานพอที่จะตระหนักได้ว่าฉันคิดว่ามันคุ้มค่าที่จะโพสต์เป็นวิธีแก้

หากสิ่งที่คุณต้องการคือการสะท้อนอย่างอื่นเมื่อออกหรือทำการล้างข้อมูลคุณสามารถใช้กับดัก

ตัว:-ดำเนินการอาจเป็นสิ่งที่คุณต้องการเป็นอย่างอื่น

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