ฉันสับสนโดยการใช้วงเล็บวงเล็บวงเล็บปีกกาใน Bash เช่นเดียวกับความแตกต่างระหว่างรูปแบบสองหรือเดี่ยวของพวกเขา มีคำอธิบายที่ชัดเจนหรือไม่?
ฉันสับสนโดยการใช้วงเล็บวงเล็บวงเล็บปีกกาใน Bash เช่นเดียวกับความแตกต่างระหว่างรูปแบบสองหรือเดี่ยวของพวกเขา มีคำอธิบายที่ชัดเจนหรือไม่?
คำตอบ:
ใน Bash testและ[เป็น shell builtins
เครื่องหมายวงเล็บเหลี่ยมคู่ซึ่งเป็นคีย์เวิร์ดเชลล์เปิดใช้งานฟังก์ชันเพิ่มเติม ตัวอย่างเช่นคุณสามารถใช้&&และ||แทนที่-aและ-oและมีตัวดำเนินการจับคู่นิพจน์ทั่วไป=~และมีผู้ประกอบการแสดงออกของการจับคู่ปกติ
นอกจากนี้ในการทดสอบอย่างง่ายวงเล็บเหลี่ยมสองชั้นดูเหมือนจะประเมินได้เร็วกว่าแบบเดี่ยวมาก
$ time for ((i=0; i<10000000; i++)); do [[ "$i" = 1000 ]]; done
real    0m24.548s
user    0m24.337s
sys 0m0.036s
$ time for ((i=0; i<10000000; i++)); do [ "$i" = 1000 ]; done
real    0m33.478s
user    0m33.478s
sys 0m0.000sเครื่องมือจัดฟันนอกเหนือจากการกำหนดชื่อตัวแปรให้ใช้สำหรับการขยายพารามิเตอร์เพื่อให้คุณสามารถทำสิ่งต่าง ๆ เช่น:
ตัดเนื้อหาของตัวแปรออก
$ var="abcde"; echo ${var%d*}
abcทำให้การทดแทนคล้ายกับ sed
$ var="abcde"; echo ${var/de/12}
abc12ใช้ค่าเริ่มต้น
$ default="hello"; unset var; echo ${var:-$default}
helloและอีกมากมาย
นอกจากนี้การขยายรั้งจะสร้างรายการของสตริงซึ่งโดยทั่วไปจะวนซ้ำในลูป:
$ echo f{oo,ee,a}d
food feed fad
$ mv error.log{,.OLD}
(error.log is renamed to error.log.OLD because the brace expression
expands to "mv error.log error.log.OLD")
$ for num in {000..2}; do echo "$num"; done
000
001
002
$ echo {00..8..2}
00 02 04 06 08
$ echo {D..T..4}
D H L P Tโปรดทราบว่าคุณลักษณะนำหน้าศูนย์และการเพิ่มขึ้นไม่พร้อมใช้งานก่อน Bash 4
ขอบคุณ gboffi สำหรับเตือนฉันเกี่ยวกับการขยายรั้ง
เครื่องหมายวงเล็บคู่ใช้สำหรับการดำเนินการทางคณิตศาสตร์ :
((a++))
((meaning = 42))
for ((i=0; i<10; i++))
echo $((a + b + (14 * c)))และพวกเขาทำให้คุณสามารถละเว้นเครื่องหมายดอลลาร์เกี่ยวกับตัวแปรจำนวนเต็มและอาร์เรย์และรวมถึงการเว้นวรรครอบตัวดำเนินการเพื่อให้สามารถอ่านได้
วงเล็บเดียวยังใช้สำหรับดัชนีอาร์เรย์ :
array[4]="hello"
element=${array[index]}ต้องใช้เครื่องหมายปีกกาสำหรับการอ้างอิงอาเรย์ (ส่วนใหญ่ / ทั้งหมด?) ทางด้านขวามือ
ความคิดเห็นของ ephemientทำให้ฉันนึกถึงว่ามีการใช้วงเล็บใน subshells ด้วยเช่นกัน และพวกเขาจะใช้ในการสร้างอาร์เรย์
array=(1 2 3)
echo ${array[1]}
2:มันเป็นเพียงระเบิดส้อมถ้าคุณเรียกมันเพิ่มเติมด้วย
                    $[expression]; นี่คือไวยากรณ์นิพจน์ทางคณิตศาสตร์เก่าที่คัดค้านสำหรับไวยากรณ์ที่ใหม่กว่าและต้องการ:$((expression))
                    bashการสร้างลำดับดังที่กล่าวไว้ด้านล่าง ( stackoverflow.com/a/8552128/2749397 ) ตามที่ฉันต้องการจะแสดงความคิดเห็นเล็กน้อยคุณลักษณะนี้ (ตามที่คุณไม่ได้พูดถึงมัน ;-) ฉัน ' m ใช้เสรีภาพในการใช้คำตอบที่ได้รับการโหวตมากที่สุดในฐานะพาหนะ ... ตัวอย่างสองตัวอย่างของตัวอักษรตามลำดับ: echo {01..12}-> 01 02 03 04 05 06 07 08 09 10 11 12(บันทึกศูนย์เริ่มต้น); ->echo {C..Q} C D E F G H I J K L M N O P Qการใช้งานหลักคือลูปเช่น  for cnt in {01..12} ; do ... ${cnt} ... ; done
                    echo {01..12..2}-> "01 03 05 07 09 11" ขอบคุณสำหรับการเตือนเกี่ยวกับลำดับ ฉันจะเพิ่มเข้าไปในคำตอบของฉัน
                    เครื่องหมายวงเล็บเดี่ยว ( [) มักจะเรียกชื่อโปรแกรม[จริง man testหรือman [สำหรับข้อมูลเพิ่มเติม ตัวอย่าง:
$ VARIABLE=abcdef
$ if [ $VARIABLE == abcdef ] ; then echo yes ; else echo no ; fi
yesวงเล็บคู่ ( [[) ทำสิ่งเดียวกัน (โดยทั่วไป) เป็นวงเล็บเดียว แต่เป็นตัวทุบตีในตัว
$ VARIABLE=abcdef
$ if [[ $VARIABLE == 123456 ]] ; then echo yes ; else echo no ; fi
noวงเล็บ ( ()) ถูกใช้เพื่อสร้าง subshell ตัวอย่างเช่น:
$ pwd
/home/user 
$ (cd /tmp; pwd)
/tmp
$ pwd
/home/userอย่างที่คุณเห็น subshell อนุญาตให้คุณทำการดำเนินการโดยไม่มีผลกระทบต่อสภาพแวดล้อมของเชลล์ปัจจุบัน
(a) เครื่องมือจัดฟัน ( {}) ใช้เพื่อระบุตัวแปรอย่างไม่น่าสงสัย ตัวอย่าง:
$ VARIABLE=abcdef
$ echo Variable: $VARIABLE
Variable: abcdef
$ echo Variable: $VARIABLE123456
Variable:
$ echo Variable: ${VARIABLE}123456
Variable: abcdef123456(b) การจัดฟันใช้เพื่อดำเนินการตามลำดับของคำสั่งในบริบทเชลล์ปัจจุบันเช่น
$ { date; top -b -n1 | head ; } >logfile 
# 'date' and 'top' output are concatenated, 
# could be useful sometimes to hunt for a top loader )
$ { date; make 2>&1; date; } | tee logfile
# now we can calculate the duration of a build from the logfileมีความแตกต่างทางวากยสัมพันธ์ที่ลึกซึ้งด้วย( )แม้ว่า (ดูการอ้างอิงทุบตี ); หลักอัฒภาค;หลังจากที่คำสั่งสุดท้ายที่อยู่ในวงเล็บคือต้องและวงเล็บ{, } ต้องถูกล้อมรอบด้วยช่องว่าง
[เป็นจริงใน builtin ทุบตี แต่มันควรจะทำหน้าที่เหมือน/bin/[เมื่อเทียบกับ[[ในตัว  [[มีคุณสมบัติที่แตกต่างกันเช่นการทำงานแบบลอจิคัลมากกว่าและบทบาทที่ต่างกัน นอกจากนี้: วงเล็บเดียวยังใช้สำหรับอาร์เรย์การแทนกระบวนการและการขยายเพิ่มเติม เครื่องหมายวงเล็บคู่ใช้สำหรับการคำนวณ วงเล็บปีกกา{}จะใช้สำหรับการจัดกลุ่มคำสั่งหรือหลากหลายประเภทของการขยายพารามิเตอร์หรือการขยายรั้งหรือการขยายลำดับ ฉันแน่ใจว่าฉันพลาดการใช้งานอื่นด้วย
                    if [ $VARIABLE == abcdef ]คือ bashism ที่แม้ว่ามันจะใช้ได้ดี แต่ก็ควรหลีกเลี่ยง ใช้ bash ( if [[ ...==...]]) อย่างชัดเจนหรือทำให้ชัดเจนว่าคุณใช้เงื่อนไขแบบดั้งเดิมมากขึ้น ( if [ "$VARIABLE" = "abcdef" ]) เนื้อหาควรเริ่มจากสคริปต์ที่เรียบง่ายและพกพาได้มากที่สุดจนกว่าพวกเขาจะต้องการคุณลักษณะเฉพาะสำหรับการทุบตี (ด้วยเหตุผลใดก็ตาม) แต่ไม่ว่าในกรณีใดเจตนาจะชัดเจน "=" และ "==" และ "[[" และ "[" ทำงานแตกต่างกันและการใช้งานควรสอดคล้องกัน
                    [ "$var" = ".."]แทนที่จะเป็น==ในขณะที่ C จะกำหนดแทนการทดสอบ (และค่อนข้างเป็นสาเหตุของข้อบกพร่อง) ... ทำไมไม่ 'T testใช้==แทน=? มีใครรู้บ้าง
                    /usr/bin/[ไม่ใช่ symlink ไป/usr/bin/testและอื่น ๆ : โปรแกรมเหล่านี้มีขนาดแตกต่างกันเล็กน้อย!
                    )เป็นส่วนหนึ่งของcaseไวยากรณ์คำสั่งเพื่อสิ้นสุดบรรทัดเคส มันไม่มีวงเล็บเปิด นี่เป็นการขว้างฉันครั้งแรกที่ฉันเห็นมัน
                    วงเล็บ
if [ CONDITION ]    Test construct  
if [[ CONDITION ]]  Extended test construct  
Array[1]=element1   Array initialization  
[a-z]               Range of characters within a Regular Expression
$[ expression ]     A non-standard & obsolete version of $(( expression )) [1][1] http://wiki.bash-hackers.org/scripting/obsolete
วงเล็บปีกกา
${variable}                             Parameter substitution  
${!variable}                            Indirect variable reference  
{ command1; command2; . . . commandN; } Block of code  
{string1,string2,string3,...}           Brace expansion  
{a..z}                                  Extended brace expansion  
{}                                      Text replacement, after find and xargsวงเล็บ
( command1; command2 )             Command group executed within a subshell  
Array=(element1 element2 element3) Array initialization  
result=$(COMMAND)                  Command substitution, new style  
>(COMMAND)                         Process substitution  
<(COMMAND)                         Process substitution วงเล็บคู่
(( var = 78 ))            Integer arithmetic   
var=$(( 20 + 5 ))         Integer arithmetic, with variable assignment   
(( var++ ))               C-style variable increment   
(( var-- ))               C-style variable decrement   
(( var0 = var1<98?9:21 )) C-style ternary operationฉันแค่อยากจะเพิ่มสิ่งเหล่านี้จากTLDP :
~:$ echo $SHELL
/bin/bash
~:$ echo ${#SHELL}
9
~:$ ARRAY=(one two three)
~:$ echo ${#ARRAY}
3
~:$ echo ${TEST:-test}
test
~:$ echo $TEST
~:$ export TEST=a_string
~:$ echo ${TEST:-test}
a_string
~:$ echo ${TEST2:-$TEST}
a_string
~:$ echo $TEST2
~:$ echo ${TEST2:=$TEST}
a_string
~:$ echo $TEST2
a_string
~:$ export STRING="thisisaverylongname"
~:$ echo ${STRING:4}
isaverylongname
~:$ echo ${STRING:6:5}
avery
~:$ echo ${ARRAY[*]}
one two one three one four
~:$ echo ${ARRAY[*]#one}
two three four
~:$ echo ${ARRAY[*]#t}
one wo one hree one four
~:$ echo ${ARRAY[*]#t*}
one wo one hree one four
~:$ echo ${ARRAY[*]##t*}
one one one four
~:$ echo $STRING
thisisaverylongname
~:$ echo ${STRING%name}
thisisaverylong
~:$ echo ${STRING/name/string}
thisisaverylongstringecho ${#ARRAY}แสดงสามเพราะองค์ประกอบแรกของARRAYประกอบด้วยสามอักขระไม่ใช่เพราะมันมีสามองค์ประกอบ! echo ${#ARRAY[@]}หากต้องการพิมพ์จำนวนการใช้องค์ประกอบ
                    ${TEST:-test}เท่ากับ$TESTว่ามีตัวแปรTESTอยู่มิฉะนั้นจะส่งคืนสตริง "test" มีอีกเวอร์ชั่นหนึ่งที่ทำอะไรได้มากกว่า: ${TEST:=test}--- ซึ่งเท่ากับ$TESTถ้ามีการทดสอบอยู่ แต่เมื่อใดก็ตามที่ไม่มีก็จะสร้างตัวแปรTESTและกำหนดค่า "ทดสอบ" และยังกลายเป็นค่าของนิพจน์ทั้งหมด
                    ความแตกต่างระหว่างการทดสอบ , [และ[[มีการอธิบายในรายละเอียดมากในBashFAQ
หากต้องการตัดเรื่องสั้นให้สั้น: ทดสอบใช้ไวยากรณ์แบบพกพาเก่าของคำสั่ง ในเชลล์เกือบทั้งหมด (เชลล์ Bourne ที่เก่าที่สุดเป็นข้อยกเว้น), [เป็นคำพ้องสำหรับการทดสอบ (แต่ต้องการอาร์กิวเมนต์สุดท้ายของ) แม้ว่าเชลล์ที่ทันสมัยทั้งหมดมีการใช้งานในตัวของ [แต่ก็ยังคงมีความสามารถในการเรียกใช้งานภายนอกของชื่อนั้นได้เช่น / bin / [
[[เป็นรุ่นที่ปรับปรุงใหม่ของมันซึ่งเป็นคำหลักไม่ใช่โปรแกรม สิ่งนี้มีผลประโยชน์ในการใช้งานง่ายดังแสดงด้านล่าง [[เข้าใจโดย KornShell และ BASH (เช่น 2.03) แต่ไม่ใช่ POSIX หรือ BourneShell ที่เก่ากว่า
และข้อสรุป:
คำสั่งทดสอบใหม่ [ควรจะใช้เมื่อไรและเมื่อไหร่? หากการพกพาไปยัง BourneShell เป็นเรื่องที่น่ากังวลควรใช้ไวยากรณ์เก่า หากในอีกทางหนึ่งสคริปต์ต้องการ BASH หรือ KornShell ไวยากรณ์ใหม่นั้นมีความยืดหยุ่นมากกว่า
()กำลังใช้
วงเล็บในคำจำกัดความของฟังก์ชัน:
function_name () { command1 ; command2 ; }นั่นคือเหตุผลที่คุณต้องหลีกเลี่ยงวงเล็บในพารามิเตอร์คำสั่ง:
$ echo (
bash: syntax error near unexpected token `newline'
$ echo \(
(
$ echo () { command echo The command echo was redefined. ; }
$ echo anything
The command echo was redefined.unset -f echo@ChanKim: help unsetดู
                    Truncate the contents of a variable
$ var="abcde"; echo ${var%d*}
abc
Make substitutions similar to sed
$ var="abcde"; echo ${var/de/12}
abc12
Use a default value
$ default="hello"; unset var; echo ${var:-$default}
hello