ฉันกำลังอ่านตัวอย่างทุบตีเกี่ยวกับifแต่บางตัวอย่างเขียนด้วยวงเล็บเหลี่ยมเดียว:
if [ -f $param ]
then
#...
fi
อื่น ๆ ด้วยวงเล็บเหลี่ยมสองชั้น:
if [[ $? -ne 0 ]]
then
start looking for errors in yourlog
fi
อะไรคือความแตกต่าง?
ฉันกำลังอ่านตัวอย่างทุบตีเกี่ยวกับifแต่บางตัวอย่างเขียนด้วยวงเล็บเหลี่ยมเดียว:
if [ -f $param ]
then
#...
fi
อื่น ๆ ด้วยวงเล็บเหลี่ยมสองชั้น:
if [[ $? -ne 0 ]]
then
start looking for errors in yourlog
fi
อะไรคือความแตกต่าง?
คำตอบ:
Single []คือการทดสอบเงื่อนไขที่สอดคล้องกับ posix shell
Double [[]]เป็นส่วนขยายของมาตรฐาน[]และรองรับโดย bash และ shell อื่น ๆ (เช่น zsh, ksh) พวกเขาสนับสนุนการดำเนินงานพิเศษ (เช่นเดียวกับการดำเนินงาน posix มาตรฐาน) ตัวอย่างเช่น: ||แทน-oและการจับคู่ regex =~กับ รายการฟูลเลอร์ของความแตกต่างที่สามารถพบได้ในส่วนคู่มือการทุบตีในการสร้างเงื่อนไข
ใช้[]เมื่อใดก็ตามที่คุณต้องการให้สคริปต์พกพาข้ามเชลล์ได้ ใช้[[]]ถ้าคุณต้องการนิพจน์แบบมีเงื่อนไขที่ไม่รองรับ[]และไม่จำเป็นต้องพกพา
[[ ]](เช่นทุบตีด้วย#!/bin/bashหรือ#!/usr/bin/env bash) คุณควรใช้ตัวเลือกแบบพกพา สคริปต์ที่สมมติว่า / bin / sh รองรับส่วนขยายเช่นนี้จะทำให้ระบบปฏิบัติการหยุดชะงักเช่น Debian และ Ubuntu รุ่นล่าสุดซึ่งไม่ได้เป็นอย่างนั้น
ความแตกต่างของพฤติกรรม
ทดสอบใน Bash 4.3.11:
POSIX vs Bash extension:
[ POSIX คือ[[เป็นส่วนขยายของBash¹ที่: https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructsคำสั่งปกติกับเวทมนตร์
[ เป็นเพียงคำสั่งปกติที่มีชื่อแปลก ๆ
]เป็นเพียงข้อโต้แย้ง[ที่ป้องกันไม่ให้มีการใช้ข้อโต้แย้งเพิ่มเติม
จริง ๆ แล้ว Ubuntu 16.04 มีไฟล์ปฏิบัติการที่/usr/bin/[ให้มาโดย coreutils แต่เวอร์ชั่นในตัวของ bash นั้นมีความสำคัญกว่า
ไม่มีอะไรเปลี่ยนแปลงในวิธีที่ Bash วิเคราะห์คำสั่ง
โดยเฉพาะอย่างยิ่ง<คือการเปลี่ยนเส้นทาง&&และ||เชื่อมคำสั่งหลายคำพร้อมกัน( )สร้าง subshells เว้นแต่จะหลบหนีไป\และการขยายคำจะเกิดขึ้นตามปกติ
[[ X ]]เป็นโครงสร้างเดียวที่ทำให้การXแยกวิเคราะห์อย่างน่าอัศจรรย์ <, &&, ||และ()ได้รับการปฏิบัติเป็นพิเศษและกฎการแยกคำที่แตกต่างกัน
นอกจากนี้ยังมีความแตกต่างต่อไปเหมือนและ==~
ใน Bashese: [เป็นคำสั่งในตัวและ[[เป็นคำหลัก: /ubuntu/445749/whats-the-difference-between-shell-builtin-and-shell-keyword
<
[[ a < b ]]: การเปรียบเทียบพจนานุกรม[ a \< b ]: เหมือนด้านบน \จำเป็นหรือไม่ก็เปลี่ยนเส้นทางเหมือนคำสั่งอื่น ๆ นามสกุลทุบตีexpr a \< b > /dev/null: POSIX เทียบเท่า²ดู: วิธีทดสอบสตริงสำหรับ lexicographic น้อยกว่าหรือเท่ากับใน Bash&& และ ||
[[ a = a && b = b ]]: จริงตรรกะและ[ a = a && b = b ]: ข้อผิดพลาดทางไวยากรณ์&&แยกวิเคราะห์เป็นตัวคั่นคำสั่ง ANDcmd1 && cmd2 [ a = a -a b = b ]: เทียบเท่า แต่เลิกใช้แล้วโดยPOSIX³[ a = a ] && [ b = b ]: POSIX และเทียบเท่าที่เชื่อถือได้(
[[ (a = a || a = b) && a = b ]]: false[ ( a = a ) ]: ข้อผิดพลาดทางไวยากรณ์()ถูกตีความว่าเป็น subshell[ \( a = a -o a = b \) -a a = b ]: เทียบเท่า แต่()เลิกใช้แล้วโดย POSIX{ [ a = a ] || [ a = b ]; } && [ a = b ]POSIX เทียบเท่า5การแยกคำและการสร้างชื่อไฟล์ตามการขยาย (แยก + glob)
x='a b'; [[ $x = 'a b' ]]: จริงไม่จำเป็นต้องใส่เครื่องหมายคำพูดx='a b'; [ $x = 'a b' ]: ข้อผิดพลาดทางไวยากรณ์ขยายเป็น [ a b = 'a b' ]x='*'; [ $x = 'a b' ]: ข้อผิดพลาดทางไวยากรณ์หากมีมากกว่าหนึ่งไฟล์ในไดเรกทอรีปัจจุบันx='a b'; [ "$x" = 'a b' ]: เทียบเท่า POSIX=
[[ ab = a? ]]: จริงเพราะมันจับคู่รูปแบบ (* ? [เป็นเวทมนตร์) ห้าม glob ขยายไฟล์ในไดเรกทอรีปัจจุบัน[ ab = a? ]: a? glob ขยายตัว ดังนั้นอาจเป็นจริงหรือเท็จขึ้นอยู่กับไฟล์ในไดเรกทอรีปัจจุบัน[ ab = a\? ]: เท็จไม่ใช่การขยาย glob=และ==เหมือนกันทั้งใน[และ[[, แต่==เป็นส่วนขยายของ Bashcase ab in (a?) echo match; esac: เทียบเท่า POSIX[[ ab =~ 'ab?' ]]: false 4 , สูญเสียเวทย์ด้วย''[[ ab? =~ 'ab?' ]]: จริง=~
[[ ab =~ ab? ]]: จริง POSIX ขยายการจับคู่นิพจน์ปกติ?ไม่ขยาย[ a =~ a ]: ข้อผิดพลาดทางไวยากรณ์ ไม่เทียบเท่าทุบตีprintf 'ab\n' | grep -Eq 'ab?': เทียบเท่า POSIX (ข้อมูลบรรทัดเดียวเท่านั้น)awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?': เทียบเท่า POSIXคำแนะนำ : ใช้เสมอ[]มักจะใช้
มี POSIX ที่เทียบเท่าสำหรับทุกคน [[ ]]สร้างฉันเห็น
ถ้าคุณใช้[[ ]]คุณ:
[เป็นเพียงคำสั่งปกติที่มีชื่อแปลก ๆ ไม่มีความหมายพิเศษเกี่ยวข้อง¹แรงบันดาลใจจากโครงสร้างที่เทียบเท่า[[...]]ใน Korn เชลล์
² แต่ล้มเหลวสำหรับบางค่าของaหรือb(เช่น+หรือindex) และทำการเปรียบเทียบตัวเลขถ้าaและbดูเหมือนเลขจำนวนเต็มฐานสิบ expr "x$a" '<' "x$b"ทำงานได้ทั้งสองอย่าง
³และยังล้มเหลวสำหรับค่าของบางส่วนaหรือbเหมือนหรือ!(
4ใน bash 3.2 ขึ้นไปและไม่สามารถเปิดใช้งานความเข้ากันได้กับ bash 3.1 (เช่นเดียวกับBASH_COMPAT=3.1)
5แม้ว่าการจัดกลุ่ม (ที่นี่พร้อมกับ{...;}กลุ่มคำสั่งแทนที่จะ(...)ใช้การเรียกใช้ subshell ที่ไม่จำเป็น) ไม่จำเป็นเนื่องจากตัวดำเนินการ||และ&&เชลล์ (ตรงข้ามกับตัวดำเนินการ||และ&& [[...]]ตัวดำเนินการ-o/ -a [ตัวดำเนินการ/ ) มีความสำคัญเท่ากัน ดังนั้น[ a = a ] || [ a = b ] && [ a = b ]จะเทียบเท่า
[]ควรอ่านเป็นตั้งค่าของฉันใช้งาน: ใช้[]ถ้าคุณไม่ต้องการที่จะสูญเสียการพกพา ตามที่ระบุไว้ที่นี่ : หากการพกพา / ความสอดคล้องกับ POSIX หรือ BourneShell เป็นเรื่องที่น่ากังวลควรใช้ไวยากรณ์เก่า หากในอีกทางหนึ่งสคริปต์ต้องการ BASH, Zsh หรือ KornShell ไวยากรณ์ใหม่มักจะมีความยืดหยุ่นมากขึ้น แต่ไม่จำเป็นต้องเข้ากันได้ย้อนหลัง ฉันควรจะไปด้วย[[ ab =~ ab? ]]ถ้าฉันสามารถและไม่ต้องกังวลเกี่ยวกับความเข้ากันได้ย้อนหลังกว่าprintf 'ab' | grep -Eq 'ab?'
ภายในวงเล็บเดียวสำหรับการทดสอบเงื่อนไข (เช่น [... ]) ผู้ประกอบการบางรายเช่นเดียว=ได้รับการสนับสนุนโดยเชลล์ทั้งหมดในขณะที่การใช้ตัวดำเนินการ==ไม่ได้รับการสนับสนุนโดยเชลล์รุ่นเก่าบางตัว
ภายในวงเล็บสองชั้นสำหรับการทดสอบเงื่อนไข (เช่น [[... ]]) ไม่มีความแตกต่างระหว่างการใช้=หรือ==ในกระสุนเก่าหรือใหม่
แก้ไข: ฉันควรทราบด้วย: ใน bash ให้ใช้เครื่องหมายวงเล็บคู่ [[... ]] ถ้าเป็นไปได้เพราะจะปลอดภัยกว่าเครื่องหมายวงเล็บเดียว ฉันจะอธิบายว่าทำไมด้วยตัวอย่างต่อไปนี้:
if [ $var == "hello" ]; then
ถ้า $ var ว่างเปล่า / ว่างนี่คือสิ่งที่สคริปต์เห็น:
if [ == "hello" ]; then
ซึ่งจะทำลายสคริปต์ของคุณ วิธีแก้คือการใช้วงเล็บคู่หรืออย่าลืมใส่เครื่องหมายคำพูดรอบตัวแปรของคุณ ( "$var") วงเล็บสองตัวคือแนวปฏิบัติการเข้ารหัสที่ดียิ่งขึ้น
[[เป็นคำหลักทุบตีคล้ายกับ (แต่มีประสิทธิภาพมากกว่า) [คำสั่ง
ดู
http://mywiki.wooledge.org/BashFAQ/031และhttp://mywiki.wooledge.org/BashGuide/TestsAndConditionals
ถ้าคุณกำลังเขียน POSIX [[ดวลจุดโทษเราขอแนะนำให้
คู่มือทุบตีพูดว่า:
เมื่อใช้กับ [[ตัวดำเนินการ '<' และ '>' จะเรียงลำดับพจนานุกรมโดยใช้ภาษาปัจจุบัน คำสั่งทดสอบใช้การสั่งซื้อ ASCII
(คำสั่งทดสอบเหมือนกับ [])