ฉันกำลังอ่านตัวอย่างทุบตีเกี่ยวกับ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
(คำสั่งทดสอบเหมือนกับ [])