เชลล์คล้าย Bourne / POSIX มีตัวดำเนินการแยก + glob และมีการเรียกใช้ทุกครั้งที่คุณออกจากการขยายพารามิเตอร์ ( $var
, $-
... ), การแทนที่คำสั่ง ( $(...)
) หรือการขยายเลขคณิต ( $((...))
) ไม่ได้ระบุไว้ในบริบทรายการ
ที่จริงแล้วคุณเรียกมันโดยไม่ได้ตั้งใจเมื่อคุณทำแทนfor name in ${array[@]}
for name in "${array[@]}"
(ที่จริงแล้วคุณควรระวังที่เรียกใช้ตัวดำเนินการนั้นโดยไม่ตั้งใจว่าเป็นแหล่งที่มาของข้อบกพร่องและจุดอ่อนด้านความปลอดภัย )
ผู้ประกอบการที่มีการกำหนดค่าด้วย$IFS
พารามิเตอร์พิเศษ (จะบอกสิ่งที่ตัวอักษรเพื่อแยก ( แต่ระวังว่าพื้นที่แท็บและการขึ้นบรรทัดใหม่ได้รับการดูแลเป็นพิเศษมี)) และ-f
ตัวเลือกที่จะปิดการใช้งาน ( set -f
) หรือเปิดใช้งาน ( set +f
) ด้วยglob
ส่วนหนึ่ง
นอกจากนี้โปรดทราบว่าในขณะที่S
อิน$IFS
คือเดิม (ในเชลล์เป้าหมายที่$IFS
มาจาก) สำหรับSeparator ใน POSIX เชลล์อักขระใน$IFS
ควรจะถูกมองว่าเป็นตัวคั่นหรือเทอร์มิเนเตอร์ (ดูตัวอย่างด้านล่าง)
ดังนั้นเพื่อแยก_
:
string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
array=($string) # invoke the split+glob operator
for i in "${array[@]}"; do # loop over the array elements.
หากต้องการดูความแตกต่างระหว่างตัวคั่นและตัวคั่นให้ลองทำดังนี้:
string='var1_var2_'
ที่จะแยกไว้ในvar1
และvar2
เท่านั้น (องค์ประกอบที่ว่างเปล่าไม่มีเสริม)
ดังนั้นเพื่อให้คล้ายกับ JavaScript split()
คุณต้องมีขั้นตอนเพิ่มเติม:
string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
temp=${string}_ # add an extra delimiter
array=($temp) # invoke the split+glob operator
(โปรดทราบว่ามันจะแบ่งค่าว่าง$string
เป็น1 (ไม่ใช่0 ) องค์ประกอบเช่น JavaScript split()
)
หากต้องการดูแท็บการรักษาพิเศษพื้นที่และการขึ้นบรรทัดใหม่ให้เปรียบเทียบ:
IFS=' '; string=' var1 var2 '
(ที่คุณได้รับvar1
และvar2
) ด้วย
IFS='_'; string='_var1__var2__'
ที่คุณจะได้รับ: ''
, var1
, ''
, ,var2
''
โปรดทราบว่าzsh
เชลล์ไม่ได้เรียกใช้ตัวดำเนินการแยก + glob โดยปริยายเช่นนั้นยกเว้นในsh
หรือksh
จำลอง ที่นั่นคุณต้องเรียกใช้มันอย่างชัดเจน $=string
สำหรับส่วนที่แยก$~string
สำหรับส่วน glob ( $=~string
สำหรับทั้งสอง) และมันยังมีตัวดำเนินการแยกที่คุณสามารถระบุตัวแยก:
array=(${(s:_:)string})
หรือเพื่อรักษาองค์ประกอบที่ว่างเปล่า:
array=("${(@s:_:)string}")
โปรดทราบว่ามีs
การแยกไม่คั่น (รวม$IFS
ถึง POSIX ที่ไม่สอดคล้องกันzsh
) มันแตกต่างจาก JavaScript split()
ในที่สตริงว่างถูกแบ่งออกเป็นองค์ประกอบ 0 (ไม่ใช่ 1)
ความแตกต่างที่โดดเด่นด้วย$IFS
-splitting คือ${(s:abc:)string}
แยกบนabc
สตริงในขณะที่มีการIFS=abc
ที่จะแยกa
, หรือb
c
ด้วยzsh
และการรักษาพิเศษที่พื้นที่แท็บหรือขึ้นบรรทัดใหม่ได้รับสามารถลบออกได้โดยการเพิ่มพวกเขาในksh93
$IFS
ในฐานะที่เป็นบันทึกประวัติศาสตร์เชลล์บอร์น (เชลล์บรรพบุรุษหรือ POSIX เชลล์สมัยใหม่) ลอกองค์ประกอบที่ว่างเปล่าเสมอ นอกจากนี้ยังมีจำนวนของข้อบกพร่องที่เกี่ยวข้องกับการแยกและการขยายตัวของ $ @ $IFS
มีค่าที่ไม่ใช่การเริ่มต้นของ ยกตัวอย่างเช่นจะไม่เทียบเท่ากับIFS=_; set -f; set -- $@
IFS=_; set -f; set -- $1 $2 $3...
แยกบน regexps
ตอนนี้สำหรับบางสิ่งที่ใกล้เคียงกับ JavaScript split()
ที่สามารถแยกการแสดงผลปกติคุณต้องพึ่งพาโปรแกรมอรรถประโยชน์ภายนอก
ใน POSIX Tool-chest awk
มีsplit
โอเปอเรเตอร์ที่สามารถแยกนิพจน์ปกติแบบขยาย (ซึ่งเป็นชุดย่อยของนิพจน์ปกติเหมือน Perl ที่สนับสนุนโดย JavaScript)
split() {
awk -v q="'" '
function quote(s) {
gsub(q, q "\\" q q, s)
return q s q
}
BEGIN {
n = split(ARGV[1], a, ARGV[2])
for (i = 1; i <= n; i++) printf " %s", quote(a[i])
exit
}' "$@"
}
string=a__b_+c
eval "array=($(split "$string" '[_+]+'))"
zsh
เปลือกมีในตัวสนับสนุนสำหรับการแสดงออกปกติ Perl เข้ากันได้ (ในของzsh/pcre
โมดูล) แต่ใช้มันเพื่อแยกสตริง แต่ที่เป็นไปได้ค่อนข้างยุ่งยาก
shell
ที่คุณใช้กับbash
ที่คุณสามารถทำได้IFS='_' read -a array <<< "${string}"