เพื่อนร่วมงานอ้างสิทธิ์เมื่อเร็ว ๆ นี้ในการตรวจสอบโค้ดว่าสิ่ง[[ ]]ก่อสร้างนั้นเป็นที่ต้องการมากกว่า[ ]ในงานสร้างเช่น
if [ "`id -nu`" = "$someuser" ] ; then
echo "I love you madly, $someuser"
fi
เขาไม่สามารถให้เหตุผลได้ มีไหม
เพื่อนร่วมงานอ้างสิทธิ์เมื่อเร็ว ๆ นี้ในการตรวจสอบโค้ดว่าสิ่ง[[ ]]ก่อสร้างนั้นเป็นที่ต้องการมากกว่า[ ]ในงานสร้างเช่น
if [ "`id -nu`" = "$someuser" ] ; then
echo "I love you madly, $someuser"
fi
เขาไม่สามารถให้เหตุผลได้ มีไหม
คำตอบ:
[[มีความประหลาดใจน้อยลงและโดยทั่วไปจะปลอดภัยกว่าการใช้งาน แต่มันไม่สามารถพกพาได้ - POSIX ไม่ได้ระบุสิ่งที่มันทำและมีเพียงหอยบางตัวเท่านั้นที่สนับสนุน (นอกเหนือจาก bash ฉันได้ยิน ksh ก็สนับสนุนเช่นกัน) ตัวอย่างเช่นคุณสามารถทำได้
[[ -e $b ]]
เพื่อทดสอบว่ามีไฟล์อยู่หรือไม่ แต่ด้วยความที่[คุณต้องอ้าง$bเพราะมันแยกอาร์กิวเมนต์และขยายสิ่งที่ชอบ"a*"(ที่[[ใช้มันตัวอักษร) สิ่งนั้นเกี่ยวข้องกับวิธีที่[จะเป็นโปรแกรมภายนอกและรับอาร์กิวเมนต์โดยปกติเหมือนกับโปรแกรมอื่น ๆ ทุกตัว (แม้ว่ามันจะเป็น builtin แต่ก็ยังไม่มีการจัดการพิเศษนี้)
[[นอกจากนี้ยังมีคุณสมบัติที่ดีอื่น ๆ เช่นการจับคู่นิพจน์ทั่วไป=~พร้อมกับตัวดำเนินการเหมือนกับที่รู้จักในภาษา C-like นี่คือหน้าดีเกี่ยวกับมัน: อะไรคือความแตกต่างระหว่างการทดสอบ[และ[[? และการทดสอบทุบตี
[[ ]] [ ]
#!/bin/shแต่จากนั้นสลับไปใช้#!/bin/bashทันทีที่ฉันใช้คุณลักษณะเฉพาะของ BASH เพื่อแสดงว่าไม่มี Bourne shell แบบพกพาอีกต่อไป
ความแตกต่างของพฤติกรรม
ความแตกต่างบางประการใน Bash 4.3.11:
POSIX vs Bash extension:
[ POSIX คือ[[ เป็นนามสกุล Bash ¹คำสั่งปกติกับเวทมนตร์
[ เป็นเพียงคำสั่งปกติที่มีชื่อแปลก ๆ
]เป็นเพียงข้อโต้แย้ง[ที่ป้องกันไม่ให้มีการใช้ข้อโต้แย้งเพิ่มเติม
จริง ๆ แล้ว 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 ที่เทียบเท่า⁵การแยกคำและการสร้างชื่อไฟล์ตามการขยาย (แยก + 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⁴, สูญเสียเวทย์ด้วย ''[[ 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เหมือนหรือ!(
⁴ใน bash 3.2 ขึ้นไปและไม่สามารถเปิดใช้งานความเข้ากันได้กับ bash 3.1 (เช่นเดียวกับBASH_COMPAT=3.1)
⁵ถึงแม้ว่าการจัดกลุ่ม (ที่นี่พร้อมกับ{...;}กลุ่มคำสั่งแทนที่จะ(...)เป็นการเรียกใช้ subshell ที่ไม่จำเป็น) ไม่จำเป็นเนื่องจากตัวดำเนินการ||และ&&ตัวดำเนินการเชลล์ (ตรงข้ามกับตัวดำเนินการ||และ&& [[...]]ตัวดำเนินการหรือตัวดำเนินการ-o/ / -a [) ดังนั้น[ a = a ] || [ a = b ] && [ a = b ]จะเทียบเท่า
[เหตุผลเดียวกัน
[[ ]]มีคุณสมบัติมากขึ้น - ผมขอแนะนำให้คุณลองดูที่เป็นขั้นสูงทุบตี Scripting คู่มือสำหรับข้อมูลเพิ่มเติมโดยเฉพาะคำสั่งทดสอบการขยายส่วนในบทที่ 7 การทดสอบ
อนึ่งในฐานะบันทึก[[ ]]แนะนำถูกนำมาใช้ใน ksh88 (เวอร์ชัน 1988 ของเชลล์ Korn)
จากเครื่องมือเปรียบเทียบการทดสอบตัวยึดหรือตัวยึดคู่ใดเร็วที่สุด? ( http://bashcurescancer.com )
วงเล็บคู่เป็น“ คำสั่งผสม” โดยที่การทดสอบและวงเล็บเดี่ยวเป็นเชลล์ในตัว (และในความเป็นจริงคือคำสั่งเดียวกัน) ดังนั้นวงเล็บเดี่ยวและวงเล็บคู่รันรหัสที่แตกต่างกัน
การทดสอบและวงเล็บเดี่ยวเป็นแบบพกพามากที่สุดเนื่องจากมีอยู่เป็นคำสั่งแยกและภายนอก อย่างไรก็ตามหากคุณใช้ BASH เวอร์ชันที่ทันสมัยจากระยะไกลวงเล็บเหลี่ยมสองตัวจะได้รับการสนับสนุน
[[จะนำมาซึ่ง แต่แล้วฉันเป็นโรงเรียนเก่าผายลมเก่า :-)
[และtestแม้ว่าเวอร์ชั่นภายนอกก็มีอยู่
PS1=...crazy stuff...และ / หรือ$PROMPT_COMMAND) สำหรับสิ่งเหล่านี้ฉันไม่ต้องการให้เกิดความล่าช้าในการดำเนินการของสคริปต์
apt-get updateถ้ามันผ่านไปนานกว่า X ชั่วโมงนับตั้งแต่วิ่งครั้งสุดท้าย มันเป็นความโล่งใจที่ยอดเยี่ยมเมื่อหนึ่งสามารถออกจากการพกพาออกจากรายการข้อ จำกัด สำหรับรหัสยาวเกินไปแล้ว
หากคุณกำลังทำตามคู่มือสไตล์ของ Google :
ทดสอบ[และ[[
[[ ... ]]ลดข้อผิดพลาดเนื่องจากไม่มีการขยายชื่อพา ธ หรือการแยกคำที่เกิดขึ้นระหว่าง[[และ]]และ[[ ... ]]ช่วยให้การจับคู่นิพจน์ปกติที่[ ... ]ไม่
# This ensures the string on the left is made up of characters in the
# alnum character class followed by the string name.
# Note that the RHS should not be quoted here.
# For the gory details, see
# E14 at https://tiswww.case.edu/php/chet/bash/FAQ
if [[ "filename" =~ ^[[:alnum:]]+name ]]; then
echo "Match"
fi
# This matches the exact pattern "f*" (Does not match in this case)
if [[ "filename" == "f*" ]]; then
echo "Match"
fi
# This gives a "too many arguments" error as f* is expanded to the
# contents of the current directory
if [ "filename" == f* ]; then
echo "Match"
fi
[[ -d ~ ]]จะคืนค่าจริง (ซึ่งหมายถึง~การขยาย/home/user) ฉันคิดว่า Google ควรมีความแม่นยำมากกว่าในการเขียน
สถานการณ์ทั่วไปที่คุณไม่สามารถใช้งานได้[[คือสคริปต์ autotools configure.ac มีเครื่องหมายวงเล็บมีความหมายพิเศษและแตกต่างกันดังนั้นคุณจะต้องใช้testแทน[หรือ[[- โปรดสังเกตว่าการทดสอบ[นั้นเป็นโปรแกรมเดียวกัน
[ถึงคาดว่าจะถูกกำหนดให้เป็นฟังก์ชัน POSIX เชลล์
[[]] วงเล็บสองชั้นไม่ถูกคัดออกภายใต้รุ่น SunOS บางรุ่นและไม่มีการเรียงลำดับทั้งหมดภายในการประกาศฟังก์ชันโดย: GNU ทุบตีรุ่น 2.02.0 (1) - ปล่อย (sparc-sun-solaris2.6)
สรุป [[ดีกว่าเพราะมันไม่ได้แยกกระบวนการอื่น ไม่มีวงเล็บหรือวงเล็บเดี่ยวช้ากว่าวงเล็บคู่เพราะจะทำกระบวนการอื่น
type [ดูสิ่งนี้
[[แตกต่างจาก[เป็นไวยากรณ์ตีความโดยล่ามบรรทัดคำสั่ง type [[ในทุบตีลองพิมพ์ unix4linux ถูกต้องที่แม้ว่า[การทดสอบBourne-shell แบบคลาสสิกจะแยกกระบวนการใหม่เพื่อกำหนดค่าความจริง[[ไวยากรณ์ (ยืมจาก ksh โดย bash, zsh ฯลฯ ) ไม่ได้
[มีอยู่แล้วใน Bash และ Dash ( /bin/shในดิสทริบิวชั่นลีนุกซ์จาก Debian ทั้งหมด)
[[กับมันรหัสเป็นสิ่งที่ดีและชัดเจน แต่จำวันนั้นเมื่อคุณจะพอร์ต scriptworks ของคุณในระบบที่มีเปลือกเริ่มต้นซึ่งไม่ได้bashหรือksh, ฯลฯ[เป็นสิ่งที่น่าเกลียดน่ารำคาญ แต่ทำงานได้AK-47ในทุกสถานการณ์