ทำไม [-n] ไม่ผิดเหมือน [-n“”]?


20

คำถามของฉันเกี่ยวกับค่าตอบแทนที่ผลิตโดยรหัสนี้:

if [ -n ]; then echo "true"; else echo "false"; fi

ภาพพิมพ์trueนี้

การทดสอบเสริมโดยใช้[ -z ]ยังพิมพ์true:

if [ -z ]; then echo "true"; else  echo "false"; fi

ในโค้ดด้านบนเหตุใดการ[ -n ]ทดสอบจึงถือว่าค่าสตริงที่ไม่ผ่านเลยไม่ใช่เป็นโมฆะ

falseรหัสด้านล่างพิมพ์ สิ่งนี้คาดว่าจะเกิดขึ้นเนื่องจากค่าสตริงที่ผ่านเป็นโมฆะและมีความยาวเป็นศูนย์

if [ -n "" ]; then echo "true"; else  echo "false"; fi

คำตอบ:


14

[x]เท่ากับ[ -nx]แม้ว่าxเริ่มต้นโดยที่-ไม่มีตัวถูกดำเนินการ

$ [ -o ] ; echo $?
0
$ [ -eq ] ; echo $?
0
$ [ -n -o ] ; echo $?
0
$ [ -n -eq ] ; echo $?
0

4
โปรดทราบว่าในอดีต[ -t ]ได้รับการทดสอบว่า stdout เป็นขั้ว (สั้น[ -t 1 ]) และเปลือกหอยบางอย่างจะยังคงทำมัน (ในกรณีของksh93เฉพาะเมื่อที่-tเป็นตัวอักษร) ดังนั้นจึงเป็นเรื่องดีที่จะใช้กว่า[ -n "$var" ] [ "$var" ]แต่ที่ยังคงล้มเหลวในการเก่า ๆtestการใช้งานสำหรับค่า$varเช่น=ซึ่งในกรณีนี้[ "" != "$var" ]หรือ[ "x$var" != x ]หรือcase $x in "")...อาจจะดีกว่า
Stéphane Chazelas

3
ทางเลือกที่น่าสนใจของ-oที่นี่ ในเปลือกหอยบางอย่างเช่นbash, -oทั้งเป็นเอก (ทดสอบถ้าตัวเลือกเป็นชุด) และไบนารี (หรือ) ผู้ประกอบการเพื่อให้สิ่งที่ชอบ[ ! -o monitor ]ไม่ชัดเจน มันคือการทดสอบว่าmonitorตัวเลือกที่ไม่ได้ตั้งค่าหรืออย่างใดอย่างหนึ่ง!หรือmonitorมีสายที่ไม่ว่างเปล่า? การตัดสินใจของกฎ POSIX: อันหลัง (แตกต่างจาก[[ ! -o monitor ]])
Stéphane Chazelas

30

[ -n ]ไม่ใช้การ-nทดสอบ

-nใน[ -n ]ไม่ได้มีการทดสอบในทุก เมื่อมีเพียงหนึ่งอาร์กิวเมนต์ระหว่าง[และ]อาร์กิวเมนต์นั้นเป็นสตริงที่ทดสอบเพื่อดูว่าว่างเปล่าหรือไม่ แม้เมื่อสตริงนั้นมีผู้นำ-มันก็ยังถูกตีความว่าเป็นตัวถูกดำเนินการไม่ทดสอบ ตั้งแต่สาย-nไม่ว่างเปล่า - มันมีตัวละครทั้งสอง-และn, ไม่เป็นศูนย์ characters-- [ -n ]ประเมินให้เป็นจริง

ในฐานะที่เป็นอิกนาซิโอ Vazquez อับราฮัมกล่าวว่าที่stringเป็นอาร์กิวเมนต์เดียว, การทดสอบดำเนินการในstringในเป็นเช่นเดียวกับการทดสอบดำเนินการเกี่ยวกับมันด้วย เมื่อเกิดขึ้นจะไม่มีอะไรพิเศษเกิดขึ้น ในและครั้งที่สองในการเป็นเพียงสายการทดสอบสำหรับความว่างเปล่า[ string ][ -n string ]string-n-n[ -n ]-n[ -n -n ]

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

ด้วยเหตุผลเดียวกับที่[ -n ]ไม่ใช้การ-nทดสอบ[ -z ]อย่าใช้การ-zทดสอบ


คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับ[ในbashโดยการตรวจสอบความช่วยเหลือสำหรับมัน สังเกตว่าเป็นเชลล์ในตัว :

$ type [
[ is a shell builtin

ดังนั้นคุณสามารถhelp [ขอความช่วยเหลือได้ที่:

$ help [
[: [ arg... ]
    Evaluate conditional expression.

    This is a synonym for the "test" builtin, but the last argument must
    be a literal `]', to match the opening `['.

testสำหรับข้อมูลเพิ่มเติมรวมถึงสิ่งที่ได้รับการสนับสนุนการทดสอบและวิธีการทำงานคุณจะต้องดูความช่วยเหลือเกี่ยวกับการ เมื่อคุณเรียกใช้คำสั่งhelp testคุณจะได้รับรายการโดยละเอียด แทนที่จะทำซ้ำทั้งหมดนี่คือส่วนเกี่ยวกับตัวดำเนินการสตริง:

      -z STRING      True if string is empty.

      -n STRING
         STRING      True if string is not empty.

      STRING1 = STRING2
                     True if the strings are equal.
      STRING1 != STRING2
                     True if the strings are not equal.
      STRING1 < STRING2
                     True if STRING1 sorts before STRING2 lexicographically.
      STRING1 > STRING2
                     True if STRING1 sorts after STRING2 lexicographically.

โปรดสังเกตว่า-n STRINGและSTRINGทำสิ่งเดียวกัน: ทดสอบว่าสตริงSTRINGนั้นไม่ว่างหรือไม่


2
คำอธิบายที่ดี
Sergiy Kolodyazhnyy

1
อาจพูดถึงว่าสิ่งนี้มีความหมายสำหรับตัวแปรที่ไม่ยกมาที่ไม่ได้ตั้งค่าเช่นนี้: paste.ubuntu.com/25831047
Sergiy Kolodyazhnyy

1
@SergiyKolodyazhnyy ฉันคิดว่ามันอาจจะดีกว่าในคำตอบที่แยกต่างหาก ตัวแปรที่ไม่ได้ตั้งค่าหรือตั้งค่า แต่ว่างเปล่าหรือมีIFSช่องว่างเท่านั้นจะทำเช่นนั้น ตัวแปรที่มีหลายคำแทนที่จะเป็นศูนย์จะให้เอฟเฟกต์อื่นและอาจทำให้การทดสอบแตกต่างไปจากเดิมอย่างสิ้นเชิง สตริงที่ปรากฏขึ้นโดยมีเจตนาเพื่อเป็นตัวถูกดำเนินการจะทำงานได้อย่างถูกต้องหากไม่มีช่องว่างหรือแท็บหรืออ้างถึง คำตอบจะยาวขึ้นและซับซ้อนมากขึ้นถ้าฉันครอบคลุมหัวข้อนี้ในวิธีที่เข้าถึงได้ หากคุณตัดสินใจที่จะโพสต์คำตอบรู้สึกอิสระที่ @ me ที่นี่เกี่ยวกับมัน!
Eliah Kagan

@Eliah Kagan คำตอบของคุณนั้นสมบูรณ์และละเอียดยิ่งขึ้นแม้ว่าคำตอบของ Ignacio Vazquez-Abrams จะตอบคำถามของฉัน
Ravi Kumar

1
ฉันคิดว่าคุณกำลังขาดหายไปเหตุผลมันคืออะไรและจะต้องมีวิธีนี้ถ้าไม่ได้[ "$var" ]จะไม่สามารถใช้งานได้เป็นแบบทดสอบเพราะอาจจะขยายตัวออกไป$var -n
..

12

[ -n ]เป็นจริงเพราะ[คำสั่ง (aka testคำสั่ง) ทำหน้าที่ตามจำนวนข้อโต้แย้งที่ได้รับ หากได้รับเพียงอาร์กิวเมนต์เดียวผลที่ได้คือ "ความจริง" ถ้าอาร์กิวเมนต์เป็นสตริงที่ไม่ว่างเปล่า "-n" เป็นสตริงที่มี 2 อักขระไม่เว้นว่างดังนั้นจึงเป็น "true"

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