สมมติว่าคุณต้องการ จำกัด บอร์นเหมือนเปลือกหอย (หอยอื่น ๆ อีกมากมายชอบcsh, tcsh, rc, esหรือfishอาร์เรย์สนับสนุน แต่การเขียนสคริปต์ที่เข้ากันได้ในเวลาเดียวกันกับบอร์นเหมือนเปลือกหอยและผู้ที่เป็นเรื่องยุ่งยากและไม่มีจุดหมายโดยทั่วไปที่พวกเขาเป็นล่ามสำหรับการที่แตกต่างกันอย่างสมบูรณ์และ ภาษาที่เข้ากันไม่ได้) โปรดทราบว่าการใช้งานมีความแตกต่างอย่างมีนัยสำคัญ
Bourne like shells ที่รองรับอาร์เรย์คือ:
ksh88(นั่นเป็นครั้งแรกที่ใช้อาร์เรย์ ksh88 ยังคงพบว่าเป็นkshUnices เชิงพาณิชย์แบบดั้งเดิมส่วนใหญ่ซึ่งเป็นพื้นฐานสำหรับsh)
- อาร์เรย์เป็นหนึ่งมิติ
- อาร์เรย์จะถูกกำหนดเป็น
set -A array foo barหรือset -A array -- "$var" ...ถ้าคุณไม่สามารถรับประกันได้ว่า$varจะไม่เริ่มต้นด้วยหรือ-+
0ดัชนีอาร์เรย์เริ่มต้นที่
a[1]=valueองค์ประกอบมากมายส่วนบุคคลจะถูกกำหนดให้เป็น
- อาร์เรย์นั้นกระจัดกระจาย นั่นคือการ
a[5]=fooทำงานแม้ว่าa[0,1,2,3,4]จะไม่ได้ตั้งค่าและจะปล่อยให้ไม่ได้ตั้งค่า
${a[5]}ในการเข้าถึงองค์ประกอบของดัชนี 5 (ไม่จำเป็นต้องเป็นองค์ประกอบที่ 6 หากอาร์เรย์ไม่มีข้อมูล) 5จะมีการแสดงออกใด ๆ ทางคณิตศาสตร์
- ขนาดอาร์เรย์และตัวห้อยถูก จำกัด (ไปที่ 4096)
${#a[@]} คือจำนวนขององค์ประกอบที่กำหนดในอาร์เรย์ (ไม่ใช่ดัชนีที่กำหนดมากที่สุด)
- ไม่มีวิธีที่จะรู้รายการของตัวห้อยที่กำหนด (นอกเหนือจากการทดสอบองค์ประกอบ 4096 แต่ละรายการด้วย
[[ -n "${a[i]+set}" ]])
$a${a[0]}เป็นเช่นเดียวกับ นั่นคืออาร์เรย์ที่จะขยายตัวแปรสเกลาร์ด้วยการให้ค่าพิเศษแก่พวกเขา
pdkshและอนุพันธ์ (นั่นคือพื้นฐานสำหรับkshและบางครั้งshของ BSD หลายแห่งและเป็นการนำโอเพนซอร์ส ksh มาใช้เพียงครั้งเดียวก่อนที่จะปล่อยแหล่ง ksh93):
ส่วนใหญ่ชอบksh88แต่ทราบ:
- การใช้งานแบบเก่าบางอย่างไม่สนับสนุน
set -A array -- foo bar( --ไม่จำเป็นต้องมี)
${#a[@]}เป็นหนึ่งบวกกับดัชนีของดัชนีที่ยิ่งใหญ่ที่สุดที่ได้รับมอบหมาย ( a[1000]=1; echo "${#a[@]}"เอาต์พุต 1,001 แม้ว่าอาร์เรย์จะมีองค์ประกอบเดียวเท่านั้น
- ในรุ่นที่ใหม่กว่าขนาดอาร์เรย์จะไม่ จำกัด อีกต่อไป (นอกเหนือจากขนาดของจำนวนเต็ม)
- รุ่นล่าสุดของ
mkshมีผู้ประกอบการพิเศษไม่กี่แรงบันดาลใจจากbash, ksh93หรือzshชอบที่ได้รับมอบหมายลาa=(x y), a+=(z), ${!a[@]}ที่จะได้รับรายชื่อของดัชนีมอบหมาย
zsh. zshอาร์เรย์โดยทั่วไปได้รับการออกแบบที่ดีขึ้นและใช้เวลาที่ดีที่สุดของkshและcshอาร์เรย์ พวกเขาคล้ายกับkshแต่มีความแตกต่างที่สำคัญ:
- ดัชนีเริ่มต้นที่ 1 ไม่ใช่ 0 (ยกเว้นใน
kshอีมูเลชัน) ซึ่งสอดคล้องกับอาร์เรย์ Bourne (พารามิเตอร์ตำแหน่ง $ @ ซึ่งzshยังแสดงเป็นอาร์เรย์ $ argv) และcshอาร์เรย์
- มันเป็นประเภทที่แยกจากตัวแปรปกติ / สเกลาร์ ผู้ให้บริการจะมีความแตกต่างกับพวกเขาและเหมือนกับที่คุณคาดหวัง
$aไม่เหมือนกัน${a[0]}แต่ขยายไปยังองค์ประกอบที่ไม่ว่างของอาร์เรย์ ( "${a[@]}"สำหรับองค์ประกอบทั้งหมดที่ต้องการksh)
- พวกเขาเป็นอาร์เรย์ปกติไม่ใช่อาร์เรย์หร็อมแหร็ม
a[5]=1ทำงานได้ แต่กำหนดองค์ประกอบทั้งหมดจาก 1 ถึง 4 สตริงว่างถ้าพวกเขาไม่ได้รับมอบหมาย ดังนั้น${#a[@]}(เช่นเดียวกับ${#a}ใน ksh คือขนาดขององค์ประกอบของดัชนี 0) คือจำนวนขององค์ประกอบในอาร์เรย์และดัชนีที่ได้รับมอบหมายมากที่สุด
- สนับสนุนอาเรย์แบบเชื่อมโยง
- รองรับโอเปอเรเตอร์จำนวนมากในการทำงานกับอาร์เรย์มีขนาดใหญ่เกินกว่าจะแสดงได้ที่นี่
a=(x y)อาร์เรย์กำหนดให้เป็น set -A a x yใช้งานได้ แต่set -A a -- x yไม่ได้รับการสนับสนุนยกเว้นในการจำลอง ksh ( --ไม่จำเป็นในการจำลอง zsh)
ksh93. (ที่นี่อธิบายถึงรุ่นล่าสุด) การทดลองที่มีการksh93พิจารณามานานแล้วสามารถพบได้ในระบบมากขึ้นเรื่อย ๆ ในขณะนี้ซึ่งเผยแพร่เป็น FOSS ยกตัวอย่างเช่นมันเป็น(ที่มันถูกแทนที่ด้วย Bourne เปลือกที่ POSIX เชลล์ยังคงอยู่บนพื้นฐาน) และของ อาร์เรย์ของมันขยายและปรับปรุง ksh88/bin/sh/usr/xpg4/bin/shksh88kshSolaris 11
a=(x y)สามารถใช้เพื่อกำหนดอาร์เรย์ แต่เนื่องจากa=(...)ยังใช้เพื่อกำหนดตัวแปรผสม ( a=(foo=bar bar=baz)) a=()เป็นที่กำกวมและประกาศตัวแปรผสมไม่ใช่อาร์เรย์
- อาร์เรย์เป็นหลายมิติ (
a=((0 1) (0 2))) และองค์ประกอบของอาร์เรย์ยังสามารถเป็นตัวแปรผสมa=((a b) (c=d d=f)); echo "${a[1].c}"ได้
a=([2]=foo [5]=bar)ไวยากรณ์สามารถนำมาใช้ในการกำหนดอาร์เรย์เบาบางในครั้งเดียว
- ยกข้อ จำกัด ด้านขนาด
- ไม่เพียง
zshแต่ผู้ประกอบการจำนวนมากได้รับการสนับสนุนเช่นกันเพื่อจัดการกับอาร์เรย์
"${!a[@]}" เพื่อดึงรายการของดัชนีอาเรย์
- อาร์เรย์ที่เชื่อมโยงได้รับการสนับสนุนเป็นชนิดแยกต่างหาก
bash. bashเป็นเปลือกของโครงการ GNU มันใช้เป็นshOS / X รุ่นล่าสุดและการกระจาย GNU / Linux บางส่วน bashอาร์เรย์ส่วนใหญ่เลียนแบบksh88คนที่มีคุณสมบัติบางอย่างของและksh93zsh
a=(x y)ได้รับการสนับสนุน. set -A a x y ไม่รองรับ a=()สร้างอาร์เรย์ที่ว่างเปล่า (ไม่มีตัวแปรประกอบbash)
"${!a[@]}" สำหรับรายการดัชนี
a=([foo]=bar)ไวยากรณ์การสนับสนุนเช่นเดียวกับคนอื่น ๆ ไม่กี่และksh93zsh
bashเวอร์ชันล่าสุดยังรองรับอาร์เรย์ที่เชื่อมโยงเป็นชนิดแยกต่างหาก
yash. มันเป็นการนำ POSIX sh ไปใช้กับ POSIX sh เมื่อไม่นานมานี้ ไม่ได้ใช้งานอย่างกว้างขวาง อาร์เรย์เป็นอีก API แบบคลีนที่คล้ายกับzsh
- อาร์เรย์ไม่กระจัดกระจาย
- ดัชนีอาร์เรย์เริ่มต้นที่ 1
- นิยาม (และประกาศ) ด้วย
a=(var value)
- องค์ประกอบแทรกลบหรือแก้ไขด้วย
arraybuiltin
array -s a 5 valueการปรับเปลี่ยน 5 THองค์ประกอบจะล้มเหลวถ้าองค์ประกอบที่ไม่ได้กำหนดไว้ล่วงหน้า
- จำนวนขององค์ประกอบในอาร์เรย์คือ
${a[#]}, ${#a[@]}เป็นขนาดขององค์ประกอบที่เป็นรายการที่
- อาร์เรย์เป็นชนิดแยกต่างหาก คุณต้อง
a=("$a")กำหนดตัวแปรสเกลาร์ใหม่เป็นอาร์เรย์ก่อนจึงจะสามารถเพิ่มหรือแก้ไของค์ประกอบได้
shอาร์เรย์จะไม่ได้รับการสนับสนุนเมื่อเรียกว่าเป็น
ดังนั้นจากนั้นคุณจะเห็นว่าการตรวจหาการรองรับอาเรย์ซึ่งคุณสามารถทำได้:
if (unset a; set -A a a; eval "a=(a b)"; eval '[ -n "${a[1]}" ]'
) > /dev/null 2>&1
then
array_supported=true
else
array_supported=false
fi
ไม่เพียงพอที่จะใช้อาร์เรย์เหล่านั้น คุณจะต้องกำหนดคำสั่ง wrapper เพื่อกำหนดอาร์เรย์ให้เป็นองค์ประกอบทั้งตัวและแต่ละส่วนและตรวจสอบให้แน่ใจว่าคุณไม่ได้พยายามสร้างอาร์เรย์แบบกระจาย
ชอบ
unset a
array_elements() { eval "REPLY=\"\${#$1[@]}\""; }
if (set -A a -- a) 2> /dev/null; then
set -A a -- a b
case ${a[0]}${a[1]} in
--) set_array() { eval "shift; set -A $1"' "$@"'; }
set_array_element() { eval "$1[1+(\$2)]=\$3"; }
first_indice=0;;
a) set_array() { eval "shift; set -A $1"' -- "$@"'; }
set_array_element() { eval "$1[1+(\$2)]=\$3"; }
first_indice=1;;
--a) set_array() { eval "shift; set -A $1"' "$@"'; }
set_array_element() { eval "$1[\$2]=\$3"; }
first_indice=0;;
ab) set_array() { eval "shift; set -A $1"' -- "$@"'; }
set_array_element() { eval "$1[\$2]=\$3"; }
first_indice=0;;
esac
elif (eval 'a[5]=x') 2> /dev/null; then
set_array() { eval "shift; $1=("'"$@")'; }
set_array_element() { eval "$1[\$2]=\$3"; }
first_indice=0
elif (eval 'a=(x) && array -s a 1 y && [ "${a[1]}" = y ]') 2> /dev/null; then
set_array() { eval "shift; $1=("'"$@")'; }
set_array_element() {
eval "
$1=(\${$1+\"\${$1[@]}"'"})
while [ "$(($2))" -ge "${'"$1"'[#]}" ]; do
array -i "$1" "$2" ""
done'
array -s -- "$1" "$((1+$2))" "$3"
}
array_elements() { eval "REPLY=\${$1[#]}"; }
first_indice=1
else
echo >&2 "Array not supported"
fi
และจากนั้นคุณสามารถเข้าถึงองค์ประกอบมากมายกับ"${a[$first_indice+n]}"รายการทั้งที่มี"${a[@]}"และใช้ฟังก์ชั่นเสื้อคลุม ( array_elements, set_array, set_array_element) เพื่อให้ได้จำนวนขององค์ประกอบของอาร์เรย์ (ใน$REPLY) ตั้งแถวเป็นแต่ละองค์ประกอบทั้งหมดหรือกำหนด
อาจไม่คุ้มค่ากับความพยายาม ฉันต้องการใช้perlหรือการ จำกัด อาร์เรย์บอร์น / POSIX "$@"เปลือก:
หากเจตนาคือให้มีไฟล์บางไฟล์ที่เชลล์แหล่งโต้ตอบของผู้ใช้กำหนดฟังก์ชันที่ใช้อาร์เรย์ภายในต่อไปนี้เป็นหมายเหตุเพิ่มเติมเล็กน้อยที่อาจมีประโยชน์
คุณสามารถกำหนดค่าzshให้อาร์เรย์เป็นเหมือนkshอาร์เรย์ในขอบเขตภายใน (ในฟังก์ชันหรือฟังก์ชันที่ไม่ระบุชื่อ)
myfunction() {
[ -z "$ZSH_VERSION" ] || setopt localoption ksharrays
# use arrays of indice 0 in this function
}
คุณยังสามารถจำลองksh(ปรับปรุงความเข้ากันได้กับkshสำหรับอาร์เรย์และพื้นที่อื่น ๆ ) ด้วย:
myfunction() {
[ -z "$ZSH_VERSION" ] || emulate -L ksh
# ksh code more likely to work here
}
ด้วยความคิดนั้นและคุณยินดีที่จะลดการสนับสนุนyashและksh88และpdkshอนุพันธ์รุ่นเก่าและตราบใดที่คุณไม่พยายามสร้างอาร์เรย์แบบกระจัดกระจายคุณควรใช้อย่างต่อเนื่อง:
a[0]=foo
a=(foo bar)(แต่ไม่ใช่a=())
"${a[#]}", "${a[@]}","${a[0]}"
ในฟังก์ชั่นเหล่านั้นที่มีในemulate -L kshขณะที่zshผู้ใช้ยังคงใช้อาร์เรย์ของเขา / เธอตามปกติวิธี zsh