อะไรคือความแตกต่างระหว่างโอเปอเรเตอร์ Bash [[vs [vs (vs (vs))


245

ฉันสับสนเล็กน้อยเกี่ยวกับสิ่งที่ตัวดำเนินการเหล่านี้ทำแตกต่างกันเมื่อใช้ในการทุบตี

[[ , [ , ( , ((

ฉันเคยเห็นคนใช้พวกเขาถ้างบเช่นนี้:

if [[condition]]

if [condition]

if ((condition))

if (condition)

4
คุณอาจต้องการดูunix.stackexchange.com/questions/tagged/testก่อน
cuonglm


3
@cuonglm แดกดันเพราะลิงก์นั้นให้คำถามนี้เป็นผลลัพธ์แรก Paradox!
บ้า

5
ฉันคิดว่าการอ่านเอกสารไม่ใช่ตัวเลือก?
การแข่งขัน Lightness ใน Orbit

34
วงเล็บและวงเล็บไม่ใช่เรื่องง่ายที่จะค้นหาในเอกสารประกอบและนั่นคือทั้งหมดที่คุณมีหากคุณไม่ทราบชื่อของคุณสมบัติเหล่านั้น
ilkkachu

คำตอบ:


257

ifคำสั่งมักจะมีลักษณะเหมือน

if commands1
then
   commands2
else
   commands3
fi

ส่วนthenคำสั่งจะถูกดำเนินการถ้ารหัสทางออกของcommands1เป็นศูนย์ หากรหัสทางออกไม่ใช่ศูนย์ดังนั้นelseประโยคจะถูกดำเนินการ commands1สามารถเรียบง่ายหรือซับซ้อน มันสามารถยกตัวอย่างเช่นเป็นลำดับหนึ่งหรือมากกว่าท่อแยกจากกันโดยหนึ่งในผู้ประกอบการ;, &, หรือ&& เงื่อนไขที่แสดงด้านล่างนี้มีเพียงกรณีพิเศษ:||ifcommands1

  1. if [ condition ]

    นี่คือtestคำสั่งเชลล์แบบดั้งเดิม มันมีอยู่ในเปลือก POSIX ทั้งหมด คำสั่งทดสอบตั้งรหัสการออกและifคำสั่งที่ทำหน้าที่ตาม การทดสอบโดยทั่วไปคือว่ามีไฟล์อยู่หรือมีหนึ่งหมายเลขเท่ากับจำนวนอื่น

  2. if [[ condition ]]

    นี่เป็นรูปแบบที่อัปเกรดใหม่testจากkshซึ่งbashและzshรองรับเช่นกัน นี้testคำสั่งนอกจากนี้ยังกำหนดรหัสทางออกและifคำสั่งที่ทำหน้าที่ตาม ในบรรดาคุณสมบัติเพิ่มเติมมันสามารถทดสอบว่าสตริงนั้นตรงกับนิพจน์ทั่วไปหรือไม่

  3. if ((condition))

    ส่วนขยายkshอื่นที่bashและzshรองรับเช่นกัน สิ่งนี้ดำเนินการทางคณิตศาสตร์ เนื่องจากผลลัพธ์ของเลขคณิตรหัสออกจะถูกตั้งค่าและifคำสั่งจะทำงานตามนั้น มันจะส่งกลับรหัสทางออกของศูนย์ (จริง) ถ้าผลลัพธ์ของการคำนวณทางคณิตศาสตร์เป็นศูนย์ ชอบ[[...]]ฟอร์มนี้ไม่ใช่ POSIX และไม่ใช่พกพา

  4. if (command)

    คำสั่งนี้รันคำสั่งในเชลล์ย่อย เมื่อคำสั่งเสร็จสมบูรณ์มันจะตั้งรหัสออกและifคำสั่งจะทำงานตามนั้น

    เหตุผลทั่วไปสำหรับการใช้ subshell เช่นนี้คือการ จำกัด ผลข้างเคียงของcommandถ้าcommandจำเป็นต้องมีการกำหนดตัวแปรหรือการเปลี่ยนแปลงอื่น ๆ เพื่อสภาพแวดล้อมของเปลือก การเปลี่ยนแปลงดังกล่าวจะไม่คงอยู่หลังจากที่ subshell เสร็จสมบูรณ์

  5. if command

    คำสั่งจะถูกดำเนินการและifคำสั่งทำหน้าที่ตามรหัสออก


24
ขอบคุณที่รวมตัวเลือกที่ 5 นั่นคือกุญแจสำคัญในการเข้าใจวิธีการใช้งานได้จริงและ underutilized อย่างน่าประหลาดใจ
ลูกไก่

4
โปรดทราบว่า[จริง ๆ แล้วเป็นไบนารีไม่ใช่คำสั่งหรือสัญลักษณ์ภายใน /binโดยทั่วไปอาศัยอยู่ใน
Julien R.

8
@JulienR จริงจะถูกสร้างขึ้นในขณะที่เป็น[ testมีรุ่นไบนารีสำหรับเหตุผลด้านความเข้ากันได้ ตรวจสอบและhelp [ help test
OldTimer

4
น่าสังเกตว่าในขณะที่ ((ไม่ใช่ POSIX $((เช่นการขยายเลขคณิตคือและมันง่ายที่จะทำให้สับสน) บ่อยครั้งวิธีแก้ปัญหาคือการใช้สิ่งที่ต้องการ[ $((2+2)) -eq 4 ]ใช้ประโยชน์จากเลขคณิตในงบสรุป
Sergiy Kolodyazhnyy

1
ฉันหวังว่าฉันจะสามารถโหวตคำตอบนี้ได้มากกว่าหนึ่งครั้ง คำอธิบายที่สมบูรณ์แบบ
Anthony Gatlin

77
  • (…)วงเล็บบ่งชี้subshell สิ่งที่อยู่ข้างในนั้นไม่ได้แสดงออกในภาษาอื่น ๆ อีกมากมาย มันเป็นรายการคำสั่ง (เช่นเดียวกับวงเล็บนอก) คำสั่งเหล่านี้จะถูกดำเนินการในกระบวนการย่อยที่แยกต่างหากดังนั้นการเปลี่ยนเส้นทางการกำหนด ฯลฯ ที่ดำเนินการภายในวงเล็บจะไม่มีผลใด ๆ นอกวงเล็บ
    • ด้วยเครื่องหมายดอลลาร์ชั้นนำ$(…)คือการทดแทนคำสั่ง : มีคำสั่งอยู่ในวงเล็บและใช้เอาต์พุตจากคำสั่งเป็นส่วนหนึ่งของบรรทัดคำสั่ง (หลังจากการขยายเพิ่มเติมยกเว้นการทดแทนอยู่ระหว่างเครื่องหมายคำพูดคู่ แต่เป็นอีกเรื่องหนึ่ง ) .
  • { … }การจัดฟันเป็นเหมือนเครื่องหมายวงเล็บในการที่พวกเขาจัดกลุ่มคำสั่ง แต่พวกเขามีอิทธิพลเฉพาะกับการแยกวิเคราะห์ โปรแกรมที่x=2; { x=4; }; echo $xพิมพ์ 4 ในขณะที่x=2; (x=4); echo $xพิมพ์ 2 (เช่นวงเล็บเป็นคำหลักจะต้องมีการคั่นและพบในตำแหน่งคำสั่ง (ดังนั้นช่องว่างหลัง{และ;ก่อน}) ในขณะที่วงเล็บไม่. นั่นเป็นเพียงการเล่นโวหารไวยากรณ์)
    • ด้วยเครื่องหมายดอลลาร์ชั้นนำ${VAR}เป็นการขยายพารามิเตอร์ซึ่งขยายไปถึงมูลค่าของตัวแปรโดยมีการแปลงพิเศษ ksh93เปลือกยังสนับสนุน${ cmd;}เป็นรูปแบบของการทดแทนคำสั่งที่ไม่วางไข่ subshell
  • ((…))วงเล็บคู่ล้อมรอบคำสั่งทางคณิตศาสตร์นั่นคือการคำนวณบนจำนวนเต็มด้วยไวยากรณ์ที่คล้ายกับภาษาการเขียนโปรแกรมอื่น ๆ ไวยากรณ์นี้ส่วนใหญ่จะใช้สำหรับการมอบหมายและในเงื่อนไข มีอยู่ใน ksh / bash / zsh เท่านั้นไม่ใช่ sh แบบธรรมดา
    • ไวยากรณ์เดียวกันนี้ใช้ในนิพจน์ทางคณิตศาสตร์$((…))ซึ่งขยายเป็นค่าจำนวนเต็มของนิพจน์
  • [ … ]วงเล็บเดียวล้อมรอบนิพจน์เงื่อนไข นิพจน์ตามเงื่อนไขส่วนใหญ่จะสร้างจากตัวดำเนินการเช่น-n "$variable"เพื่อทดสอบว่าตัวแปรว่างเปล่าหรือไม่และ-e "$file"เพื่อทดสอบว่ามีไฟล์อยู่หรือไม่ โปรดทราบว่าคุณต้องการช่องว่างรอบตัวดำเนินการแต่ละตัว (เช่น[ "$x" = "$y" ]ไม่ใช่[ "$x"="$y" ]) และช่องว่างหรือตัวอักษรที่เหมือน;ทั้งด้านในและด้านนอกวงเล็บ (เช่น[ -n "$foo" ]ไม่ใช่[-n "$foo"])
  • [[ … ]]วงเล็บคู่เป็นรูปแบบทางเลือกของนิพจน์เงื่อนไขใน ksh / bash / zsh ด้วยคุณสมบัติเพิ่มเติมบางอย่างเช่นคุณสามารถเขียน[[ -L $file && -f $file ]]เพื่อทดสอบว่าไฟล์นั้นเป็นลิงก์สัญลักษณ์ไปยังไฟล์ปกติหรือ[ -L "$file" ] && [ -f "$file" ]ไม่ ดูทำไมการขยายพารามิเตอร์ด้วยช่องว่างโดยไม่มีเครื่องหมายคำพูดทำงานในวงเล็บใหญ่คู่ [[แต่ไม่ใช่วงเล็บปีกกาเดียว [? สำหรับเพิ่มเติมในหัวข้อนี้

ในเชลล์คำสั่งทุกคำสั่งเป็นคำสั่งแบบมีเงื่อนไข: คำสั่งทุกคำสั่งมีสถานะการส่งคืนซึ่งเป็น 0 บ่งชี้ถึงความสำเร็จหรือจำนวนเต็มระหว่าง 1 ถึง 255 (และอาจมากขึ้นในบางเชลล์) บ่งชี้ความล้มเหลว [ … ]คำสั่ง (หรือ[[ … ]]รูปแบบไวยากรณ์) เป็นคำสั่งโดยเฉพาะอย่างยิ่งซึ่งยังสามารถสะกดtest …และประสบความสำเร็จเมื่อไฟล์ที่มีอยู่หรือเมื่อสตริงเป็นไม่ว่างเปล่าหรือเป็นจำนวนมากเมื่อมีขนาดเล็กกว่าที่อื่น ฯลฯ((…))รูปแบบไวยากรณ์ประสบความสำเร็จเมื่อจำนวน ไม่ใช่ศูนย์ นี่เป็นตัวอย่างของเงื่อนไขในเชลล์สคริปต์:

  • ทดสอบว่าmyfileมีสตริงหรือไม่hello:

    if grep -q hello myfile; then 
  • หากmydirเป็นไดเรกทอรีให้เปลี่ยนเป็นและทำสิ่งต่างๆ:

    if cd mydir; then
      echo "Creating mydir/myfile"
      echo 'some content' >myfile
    else
      echo >&2 "Fatal error. This script requires mydir to exist."
    fi
  • ทดสอบว่ามีไฟล์ชื่อmyfileในไดเรกทอรีปัจจุบันหรือไม่:

    if [ -e myfile ]; then 
  • เหมือนกัน แต่ยังรวมถึงลิงค์สัญลักษณ์ห้อยต่องแต่ง:

    if [ -e myfile ] || [ -L myfile ]; then 
  • ทดสอบว่าค่าของx(ซึ่งสันนิษฐานว่าเป็นตัวเลข) อย่างน้อย 2 หรือสามารถพกพาได้:

    if [ "$x" -ge 2 ]; then 
  • ทดสอบว่าค่าของx(ซึ่งสันนิษฐานว่าเป็นตัวเลข) อย่างน้อย 2 ใน bash / ksh / zsh:

    if ((x >= 2)); then 

โปรดทราบว่าวงเล็บเดียวรองรับ-aแทน&&ดังนั้นหนึ่งสามารถเขียน: [ -L $file -a -f $file ]ซึ่งเป็นจำนวนอักขระที่เหมือนกันภายในวงเล็บโดยไม่ต้องเพิ่ม[และ]...
Alexis Wilke

6
@AlexisWilke ตัวดำเนินการ-aและ-oมีปัญหาเพราะสามารถแยกวิเคราะห์ได้ไม่ถูกต้องหากตัวถูกดำเนินการบางตัวที่เกี่ยวข้องดูเหมือนตัวดำเนินการ นั่นเป็นเหตุผลที่ฉันไม่พูดถึงพวกเขา: พวกเขาไม่มีประโยชน์และไม่ได้ผลเสมอไป และไม่เคยเขียนการขยายตัวแปรที่ไม่มีคำที่ไม่มีเหตุผลที่ดี: ใช้ได้[[ -L $file -a -f $file ]]แต่มีวงเล็บเดียวที่คุณต้องการ[ -L "$file" -a -f "$file" ](ซึ่งก็โอเคเช่นถ้า$fileเริ่มต้นด้วย/หรือเสมอ./)
Gilles

โปรดทราบว่ามัน[[ -L $file && -f $file ]](ไม่มี-aกับ[[...]]ตัวแปร)
Stéphane Chazelas

18

จากเอกสาร bash :

(list)รายการจะถูกดำเนินการในสภาพแวดล้อมของ subshell (ดูคำสั่งการดำเนินการด้านสิ่งแวดล้อมด้านล่าง) การกำหนดตัวแปรและคำสั่ง builtin ที่ส่งผลกระทบต่อสภาพแวดล้อมของเชลล์จะไม่มีผลบังคับใช้หลังจากคำสั่งเสร็จสิ้น สถานะการส่งคืนคือสถานะการออกของรายการ

ในคำอื่น ๆ ที่คุณให้แน่ใจว่าสิ่งที่เกิดขึ้นในรายการ '(เช่นcd) ไม่มีผลนอกและ( )สิ่งเดียวที่จะรั่วไหลเป็นรหัสทางออกของคำสั่งสุดท้ายหรือมีset -eคำสั่งแรกที่สร้างข้อผิดพลาด (นอกเหนือจากไม่กี่เช่นif, whileฯลฯ )

((expression))นิพจน์ได้รับการประเมินตามกฎที่อธิบายไว้ด้านล่างภายใต้การประเมิน ARITHMETIC หากค่าของนิพจน์ไม่ใช่ศูนย์สถานะการส่งคืนจะเป็น 0 มิฉะนั้นสถานะการส่งคืนคือ 1 ซึ่งเทียบเท่ากับให้ "expression"

นี่คือส่วนขยายทุบตีช่วยให้คุณสามารถทำคณิตศาสตร์ สิ่งนี้ค่อนข้างคล้ายกับการใช้exprโดยไม่มีข้อ จำกัด ทั้งหมดexpr(เช่นมีช่องว่างทุกหนทุกแห่งการหลบหนี*ฯลฯ )

[[ expression ]]ส่งคืนสถานะ 0 หรือ 1 ขึ้นอยู่กับการประเมินผลของนิพจน์เงื่อนไขแบบนิพจน์ การแสดงออกประกอบด้วยกลุ่มที่อธิบายไว้ด้านล่างภายใต้การแสดงออกตามเงื่อนไข การแยกคำและการขยายชื่อพา ธ จะไม่ดำเนินการกับคำระหว่าง [[และ]]; การขยายตัวตัวหนอนพารามิเตอร์และการขยายตัวแปรการขยายเลขคณิตการทดแทนคำสั่งการทดแทนกระบวนการและการลบเครื่องหมายถูกดำเนินการ ตัวดำเนินการแบบมีเงื่อนไขเช่น -f ต้องไม่ถูกยกให้เป็นที่รู้จัก

เมื่อใช้กับ [[ตัวดำเนินการ <และ> จะเรียงลำดับพจนานุกรมโดยใช้ภาษาปัจจุบัน

นี่เป็นการทดสอบขั้นสูงเพื่อเปรียบเทียบสตริงตัวเลขและไฟล์เช่นtestข้อเสนอ แต่มีประสิทธิภาพยิ่งขึ้น

[ expr ]ส่งคืนสถานะ 0 (จริง) หรือ 1 (false) ขึ้นอยู่กับการประเมินผลของนิพจน์เงื่อนไขแบบ expr แต่ละโอเปอเรเตอร์และโอเปอเรเตอร์และต้องเป็นอาร์กิวเมนต์ที่แยกต่างหาก การแสดงออกประกอบด้วยพรรคที่อธิบายไว้ข้างต้นภายใต้การแสดงออกตามเงื่อนไข การทดสอบไม่ยอมรับตัวเลือกใด ๆ และไม่ยอมรับและเพิกเฉยต่อข้อโต้แย้งของ - เป็นการบ่งบอกถึงจุดสิ้นสุดของตัวเลือก

[ ... ]

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

โปรดทราบว่าในกรณีของbash, [และtestมีฟังก์ชั่น (ตามที่กล่าวไว้ในความคิดเห็น) ยังสวยมากข้อ จำกัด เดียวกันกับ


1
แม้ว่าtestและ[เป็นคำสั่งในตัวใน Bash แต่เป็นไปได้ว่ามีไบนารีภายนอกอยู่ด้วย
ilkkachu

1
ไบนารีภายนอกสำหรับ[ไม่ใช่ลิงก์สัญลักษณ์ไปยังtestระบบที่ทันสมัยที่สุด
Random832

1
อย่างใดฉันคิดว่ามันสนุกที่พวกเขารำคาญที่จะสร้างสองไบนารีแยกกันซึ่งทั้งสองมีสิ่งที่พวกเขาต้องการเพียงแค่แทนที่จะรวมพวกเขาและเพิ่มเงื่อนไขสองสามอย่าง แม้ว่าจริง ๆ แล้วstrings /usr/bin/testแสดงว่ามันมีข้อความช่วยเหลือด้วยดังนั้นฉันไม่รู้ว่าจะพูดอะไร
ilkkachu

2
@ Random832 ฉันได้รับจุดของคุณเกี่ยวกับเหตุผล GNU เพื่อหลีกเลี่ยงพฤติกรรม arg0 ที่ไม่คาดคิด แต่เกี่ยวกับความต้องการ POSIX ฉันจะไม่ยืนยัน ในขณะที่testคำสั่งนั้นจำเป็นต้องมีอยู่อย่างชัดเจนว่าเป็นคำสั่งที่ยึดตามไฟล์แบบสแตนด์อโลนโดยมาตรฐาน แต่ก็ไม่มีอะไรที่ระบุว่า[จำเป็นต้องมีการใช้งานชุดตัวเลือกด้วยเช่นกัน ตัวอย่างเช่น Solaris 11 ไม่ได้ให้การ[ปฏิบัติการใด ๆแต่ก็เป็นไปตามมาตรฐาน POSIX อย่างสมบูรณ์
jlliagre

2
(ทางออก 1) มีผลกระทบนอกวงเล็บ
อเล็กซานเด

14

[ VS [[

คำตอบนี้จะครอบคลุม[VS [[ย่อยของคำถาม

ความแตกต่างบางประการใน Bash 4.3.11:

  • POSIX vs Bash extension:

  • คำสั่งปกติกับเวทมนตร์

    • [ เป็นเพียงคำสั่งปกติที่มีชื่อแปลก ๆ

      ]เป็นเพียงข้อโต้แย้ง[ที่ป้องกันไม่ให้มีการใช้ข้อโต้แย้งเพิ่มเติม

      จริง ๆ แล้ว Ubuntu 16.04 มีไฟล์ปฏิบัติการที่/usr/bin/[ให้มาโดย coreutils แต่เวอร์ชั่นในตัวของ bash นั้นมีความสำคัญกว่า

      ไม่มีการเปลี่ยนแปลงในวิธีที่ Bash วิเคราะห์คำสั่ง

      โดยเฉพาะอย่างยิ่ง<คือการเปลี่ยนเส้นทาง&&และ||เชื่อมคำสั่งหลาย ๆ คำสั่ง( )สร้าง subshells เว้นแต่จะหลบหนีไป\และการขยายคำจะเกิดขึ้นตามปกติ

    • [[ X ]]เป็นโครงสร้างเดียวที่ทำให้การXแยกวิเคราะห์อย่างน่าอัศจรรย์ <, &&, ||และ()ได้รับการปฏิบัติเป็นพิเศษและกฎการแยกคำที่แตกต่างกัน

      นอกจากนี้ยังมีความแตกต่างต่อไปเหมือนและ==~

      ใน Bashese: [เป็นคำสั่งในตัวและ[[เป็นคำหลัก: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword

  • <

  • && และ ||

    • [[ 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
    • =และ==เหมือนกันทั้งใน[และ[[, แต่==เป็นส่วนขยายของ Bash
    • case 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 ที่เทียบเท่าสำหรับการ[[ ]]สร้างทุกครั้งที่ฉันเห็น

ถ้าคุณใช้[[ ]]คุณ:

  • สูญเสียการพกพา
  • บังคับให้ผู้อ่านเรียนรู้ความซับซ้อนของส่วนขยาย bash อื่น [เป็นเพียงคำสั่งปกติที่มีชื่อแปลก ๆ ไม่มีความหมายพิเศษเกี่ยวข้อง

¹แรงบันดาลใจจากสิ่ง[[...]]ก่อสร้างที่เทียบเท่าใน 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แม้ว่าการจัดกลุ่ม (ที่นี่พร้อมกับ{...;}กลุ่มคำสั่งแทนที่จะเป็นกลุ่ม(...)ย่อยที่ไม่จำเป็น) ไม่จำเป็นเนื่องจากตัวดำเนินการ||และ&&เชลล์ (ตรงข้ามกับตัวดำเนินการ||และ&& [[...]]ตัวดำเนินการหรือ-o/ -a [ตัวดำเนินการ/ ) มีลำดับความสำคัญเท่ากัน ดังนั้น[ a = a ] || [ a = b ] && [ a = b ]จะเทียบเท่า


@ StéphaneChazelasขอบคุณสำหรับข้อมูล! ฉันได้เพิ่มexprคำตอบแล้ว คำว่า "Bash extension" ไม่ได้หมายความว่า Bash เป็นเชลล์ตัวแรกที่เพิ่มไวยากรณ์การเรียนรู้ POSIX sh กับ Bash นั้นเพียงพอแล้วที่จะทำให้ฉันบ้า
Ciro Santilli 新疆改造中心法轮功六四事件

ดูman testว่าคุณพยายามman [และหลงทาง ที่จะอธิบายตัวแปร POSIX
Jonathan Komar

13

ตัวอย่างบางส่วน:

การทดสอบแบบดั้งเดิม:

foo="some thing"
# check if value of foo is not empty
if [ -n "$foo" ] ; then... 
if test -n "$foo" ; then... 

testและ[เป็นคำสั่งเหมือนคนอื่น ๆ ดังนั้นตัวแปรจึงแบ่งออกเป็นคำต่าง ๆ เว้นแต่ว่าจะอยู่ในเครื่องหมายคำพูด

การทดสอบรูปแบบใหม่

[[ ... ]] เป็นโครงสร้างเชลล์พิเศษ (ใหม่กว่า) ซึ่งทำงานแตกต่างกันเล็กน้อยสิ่งที่ชัดเจนที่สุดคือการที่มันไม่ได้ใช้ตัวแปรแบ่งคำ

if [[ -n $foo ]] ; then... 

บางเอกสารเกี่ยวกับ[และ[[ที่นี่

การทดสอบทางคณิตศาสตร์:

foo=12 bar=3
if (( $foo + $bar == 15 )) ; then ...  

คำสั่ง "ปกติ":

ทั้งหมดข้างต้นทำหน้าที่เหมือนคำสั่งปกติและifสามารถใช้คำสั่งใด ๆ :

# grep returns true if it finds something
if grep pattern file ; then ...

หลายคำสั่ง:

หรือเราสามารถใช้หลายคำสั่ง การห่อชุดคำสั่งในการ( ... )รันคำสั่งในเชลล์ย่อยสร้างสำเนาชั่วคราวของสถานะเชลล์ (ไดเร็กทอรีการทำงานตัวแปร) หากเราจำเป็นต้องเรียกใช้โปรแกรมบางโปรแกรมชั่วคราวในไดเรกทอรีอื่น:

# this will move to $somedir only for the duration of the subshell 
if ( cd $somedir ; some_test ) ; then ...

# while here, the rest of the script will see the new working
# directory, even after the test
if cd $somedir ; some_test ; then ...

1

คำสั่งการจัดกลุ่ม

Bash มีสองวิธีในการจัดกลุ่มรายการคำสั่งที่จะดำเนินการเป็นหน่วย

( list )การวางรายการคำสั่งระหว่างวงเล็บทำให้เกิดสภาวะแวดล้อม subshell ที่จะสร้างและแต่ละคำสั่งในรายการที่จะดำเนินการใน subshell นั้น เนื่องจากรายการจะถูกดำเนินการใน subshell การกำหนดตัวแปรจึงยังคงมีผลหลังจาก subshell เสร็จสมบูรณ์

$ a=1; (a=2; echo "inside: a=$a"); echo "outside: a=$a"
inside: a=2
outside: a=1

{ list; }วางรายการของคำสั่งระหว่างวงเล็บปีกกาทำให้เกิดรายการที่จะดำเนินการในบริบทเปลือกปัจจุบัน ไม่มีการสร้างเชลล์ย่อย จำเป็นต้องใช้รายการอัฒภาค (หรือขึ้นบรรทัดใหม่) แหล่ง

${} Parameter expansion Ex:  ANIMAL=duck; echo One $ANIMAL, two ${ANIMAL}s
$() Command substitution Ex: result=$(COMMAND) 
$(()) Arithmetic expansion Ex: var=$(( 20 + 5 )) 

โครงสร้างแบบมีเงื่อนไข

คร่อมเดี่ยวเช่น[]
สำหรับการเปรียบเทียบ==, !=, <,และ>และควรใช้และสำหรับการเปรียบเทียบเชิงตัวเลขeq, ne,ltและgtควรใช้

ตัวยึดเสริมเช่น[[]]

ในตัวอย่างข้างต้นทั้งหมดเราใช้วงเล็บเดียวเท่านั้นเพื่อล้อมรอบนิพจน์เงื่อนไข แต่ bash อนุญาตให้วงเล็บคู่ซึ่งทำหน้าที่เป็นรุ่นปรับปรุงของไวยากรณ์วงเล็บเดี่ยว

สำหรับการเปรียบเทียบ==, !=, <,และ>สามารถใช้งานได้อย่างแท้จริง

  • [เป็นคำพ้องสำหรับคำสั่งทดสอบ แม้ว่ามันจะถูกสร้างไว้ในเชลล์มันจะสร้างกระบวนการใหม่
  • [[ เป็นรุ่นที่ปรับปรุงใหม่ของมันซึ่งเป็นคำหลักไม่ใช่โปรแกรม
  • [[เป็นที่เข้าใจกันโดยและKornBash

แหล่ง

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