สมมติว่าคุณต้องการ จำกัด บอร์นเหมือนเปลือกหอย (หอยอื่น ๆ อีกมากมายชอบcsh
, tcsh
, rc
, es
หรือfish
อาร์เรย์สนับสนุน แต่การเขียนสคริปต์ที่เข้ากันได้ในเวลาเดียวกันกับบอร์นเหมือนเปลือกหอยและผู้ที่เป็นเรื่องยุ่งยากและไม่มีจุดหมายโดยทั่วไปที่พวกเขาเป็นล่ามสำหรับการที่แตกต่างกันอย่างสมบูรณ์และ ภาษาที่เข้ากันไม่ได้) โปรดทราบว่าการใช้งานมีความแตกต่างอย่างมีนัยสำคัญ
Bourne like shells ที่รองรับอาร์เรย์คือ:
ksh88
(นั่นเป็นครั้งแรกที่ใช้อาร์เรย์ ksh88 ยังคงพบว่าเป็นksh
Unices เชิงพาณิชย์แบบดั้งเดิมส่วนใหญ่ซึ่งเป็นพื้นฐานสำหรับ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/sh
ksh88
ksh
Solaris 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 มันใช้เป็นsh
OS / X รุ่นล่าสุดและการกระจาย GNU / Linux บางส่วน bash
อาร์เรย์ส่วนใหญ่เลียนแบบksh88
คนที่มีคุณสมบัติบางอย่างของและksh93
zsh
a=(x y)
ได้รับการสนับสนุน. set -A a x y
ไม่รองรับ a=()
สร้างอาร์เรย์ที่ว่างเปล่า (ไม่มีตัวแปรประกอบbash
)
"${!a[@]}"
สำหรับรายการดัชนี
a=([foo]=bar)
ไวยากรณ์การสนับสนุนเช่นเดียวกับคนอื่น ๆ ไม่กี่และksh93
zsh
bash
เวอร์ชันล่าสุดยังรองรับอาร์เรย์ที่เชื่อมโยงเป็นชนิดแยกต่างหาก
yash
. มันเป็นการนำ POSIX sh ไปใช้กับ POSIX sh เมื่อไม่นานมานี้ ไม่ได้ใช้งานอย่างกว้างขวาง อาร์เรย์เป็นอีก API แบบคลีนที่คล้ายกับzsh
- อาร์เรย์ไม่กระจัดกระจาย
- ดัชนีอาร์เรย์เริ่มต้นที่ 1
- นิยาม (และประกาศ) ด้วย
a=(var value)
- องค์ประกอบแทรกลบหรือแก้ไขด้วย
array
builtin
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