BASH: หรือโอเปอเรเตอร์สำหรับตำแหน่ง $ 1


0

ฉันประสบปัญหาบางอย่างที่ตัวดำเนินการ OR ไม่ทำงานในราคา $ 1 เช่น:

if [[ "$1" != '1' || '2' ]]
        then
               echo "BAD"
        else
               echo "OK"
        fi

เมื่อฉันทำการทดสอบนี้ไม่ว่าจะเป็น $ 1 อะไร BAD ก็จะปรากฏขึ้นเสมอ

ฉันจะผูก $ 1 เป็น 1 หรือ 2 เท่านั้นได้อย่างไร


นี่เป็นข้อผิดพลาดทั่วไป ฉันเห็นมันมากกับโปรแกรมเมอร์มือใหม่ อย่างไรก็ตามมันไม่ใช่ว่าตรรกะบูลีนทำงานอย่างไร ลองนึกภาพการใส่วงเล็บ คุณจะนำมันไปใช้งานที่ไหน หมายเหตุมีบางภาษาที่คุณสามารถถามได้if $1 is not in {'1', '2' } then …(ดูตัวอย่างกรณีเป็น bash)
ctrl-alt-delor

คำตอบ:


5

ด้วยshไวยากรณ์มาตรฐาน(ดังนั้นจึงไม่ได้รับการยอมรับโดยbashเท่านั้น แต่เชลล์ที่รองรับ POSIX อื่น ๆ ทั้งหมด):

case $1 in
  (1 | 2) echo OK;;
  (*) echo BAD;;
esac

หรือ:

if [ "$1" = 1 ] || [ "$1" = 2 ]; then
  echo OK
else
  echo BAD
fi

(โปรดทราบว่ามันเป็นการเปรียบเทียบสตริงแบบไบต์ต่อไบต์ 01, 1e0, 1.0, 20/20, 0x1 จะถูกพิจารณาว่าเป็น BAD แม้ว่าตัวเลขจะถือว่าเป็นแบบเดียวกันกับตัวเลข1)

โปรดทราบว่า=/ !=ผู้ประกอบการในbash's [[...]]สร้าง (คัดลอกมาจากksh) เป็นจริงรูปแบบการจับคู่ผู้ประกอบการเมื่อเทียบกับผู้ประกอบการเท่าเทียมกันดังนั้นในกรณีพิเศษนี้ที่คุณต้องการเพื่อให้ตรงกับตัวอักษรตัวเดียวคุณยังสามารถใช้[[ $1 != [12] ]]เช่นคุณสามารถทำcase $1 in ([12])ในมาตรฐานshไวยากรณ์


ความคิดอันงดงามพร้อมเคส! Dunno ฉันไม่ได้ใช้มันด้วยตัวเอง)
faceless

4

เหตุผลที่คุณเข้าไปในBADสาขาของifคำแถลงก็คือการทดสอบ

[[ "$1" != '1' || '2' ]]

การทดสอบครั้งแรก$1ว่าไม่ได้เป็น1และไม่ได้BADถูกพิมพ์ ถ้าเป็น2จะได้รับการประเมินว่าเป็นการทดสอบ สตริงที่ชอบ2เป็นจริงเสมอและBADถูกพิมพ์

แทน:

if [ "$1" != '1' ] && [ "$1" != '2' ]; then

หรือด้วยการทดสอบทางคณิตศาสตร์

if [ "$1" -ne 1 ] && [ "$1" -ne 2 ]; then

หรือโดยใช้การประเมินทางคณิตศาสตร์

if (( $1 != 1 )) && (( $1 != 2 )); then

1
if [[ "$1" != '1' || "$1" != '2' ]]
then
               echo "BAD"
else
               echo "OK"
fi

จากนั้น! = คำสั่งจะต้องทำซ้ำสำหรับค่าไม่เท่ากับ 2 และ 1


ผลลัพธ์จะเหมือนกัน
faceless

1

ตรรกะของ($1 != 1) OR ($1 != 2)ข้อบกพร่อง

หาก$1เป็นเช่น1นั้นจะไม่เท่ากับ2การทดสอบจะเป็นจริง
นอกจากนี้หาก$1เป็นเช่น2นั้นจะไม่เท่ากับ1ดังนั้นการทดสอบจะเป็นจริงเช่นกัน ในระยะสั้นการทดสอบจะเป็นจริงเสมอ

คุณควรทดสอบความเท่าเทียมกันดังนี้($1 == 1) or ($1 == 2):

if [[ ($1 == '1') || ($1 == '2') ]]; then
    echo "$1 OK"
else
    echo "$1 BAD"
fi

หรือง่ายกว่า (เป็น ksh, bash หรือ zsh):

[[ $1 == [12] ]] && echo "$1 OK" || echo "$1 BAD"

หรือใช้ไวยากรณ์ sh (พกพาไปยังเปลือก POSIX ทั้งหมด):

if [ "$1" = '1' ] || [ "$1" = '2' ]; then
            echo "$1 OK"
else
            echo "$1 BAD"
fi

หรือด้วยสำนวนกรณี:

case $1 in
    (1 | 2) echo "$1 OK"  ;;
    (*) echo BAD "$1 BAD" ;;
esac

ข้างต้นทั้งหมดเป็นการเปรียบเทียบสตริงถ้าคุณต้องการเปรียบเทียบเป็นตัวเลขคุณสามารถทำได้:

if [ "$1" -eq 1 ] || [ "$1" -eq 2 ]; then
            echo "$1 OK"
else
            echo "$1 BAD"
fi

แต่ที่จะไม่ทำงานหาก$1เป็น1.0หรือ1e0หรือเทียบเท่าหลายตัวเลขอื่น ๆ 1ที่จะ จะทำงานร่วมกับ01หรือ0001แม้ว่า


2
โปรดทราบว่าสิ่งที่ได้รับการสนับสนุน[ "$1" -eq 1 ]จะแตกต่างกันจากเชลล์ / [ไปยังเชลล์ / [(และเป็นการฉีดคำสั่งโดยพลการในบางกรณีหาก$1มาจากแหล่งที่ไม่น่าเชื่อถือ) ด้วย ksh93 ที่จะกลับมาจริงสำหรับ 1.0 หรือ 1E0 หรือ 20/20 และบางครั้งด้วย% RANDOM ที่ 2 'a[$(reboot)]'และการรีบูตด้วย
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.