อาร์เรย์ที่เกี่ยวข้องในเชลล์สคริปต์


11

ฉันเห็นเคล็ดลับสำหรับการใช้อาร์เรย์เชื่อมโยงในเชลล์สคริปต์ ตัวอย่างเช่นprint array["apples"]สามารถสคริปต์เป็นecho \$array$keyตำแหน่งที่สำคัญ = แอปเปิ้ล

อย่างไรก็ตามไม่มีการพูดถึงวิธีสร้างคีย์เพื่อวนซ้ำแถวลำดับ วิธีเดียวที่ฉันคิดได้ก็คือเก็บคีย์ไว้ในตัวแปรที่คั่นด้วยช่องว่างดังนั้นฉันสามารถใช้ for-loop เพื่อวนซ้ำในอาร์เรย์

ดังนั้นมีวิธีอื่นในการจัดเก็บคีย์เพื่อใช้ในภายหลังหรือไม่


5
ถ้าคุณกำลังพยายามที่จะใช้เชื่อมโยงอาร์เรย์ในสคริปต์เปลือกมันอาจจะเป็นไปได้ว่าโครงการของคุณมีความซับซ้อนเกินไปสำหรับสคริปต์เปลือก :)
มาร์ตินฟอน Wittich

@Martinvon ทำไมล่ะ ฉันมีเชลล์สคริปต์ที่รันสคริปต์ SQL บนหนึ่งใน 3 ของสกีมาฐานข้อมูลที่เป็นไปได้ สคีมาที่ต้องการจะรวมอยู่ในชื่อไฟล์พร้อมตัวย่อ ฉันต้องการการแมประหว่างตัวย่อนี้กับชื่อสคีมาที่แท้จริง มีวิธีใดที่ดีไปกว่าอาเรย์แบบเชื่อมโยงการพิจารณาชื่อสคีมาที่แท้จริง (ไม่ใช่ตัวย่อ) อาจแตกต่างกันระหว่างสภาพแวดล้อมดังนั้นตัวแปรอาเรย์ (ซึ่งสามารถตั้งค่าได้เพียงครั้งเดียว) จึงสมบูรณ์แบบ
Slav

2
@Slav ฉันไม่ได้โต้เถียงกับอาเรย์อาร์เรย์เพียงแค่เทียบกับสคริปต์เชลล์ที่ต้องการความซับซ้อนเช่นนั้น แต่นั่นเป็นเพียงความชอบส่วนตัวของฉัน; ฉันมักจะจับตัวเองเริ่มเขียนเชลล์สคริปต์แล้วเขียนมันใหม่ใน Perl ทันทีเมื่อฉันรู้ว่าฉันเกินขีดจำกัดความซับซ้อน
Martin von Wittich

คำตอบ:


20

เชลล์ที่มีอาร์เรย์เชื่อมโยง

เชลล์สมัยใหม่บางตัวมีอาร์เรย์เชื่อมโยง: ksh93, bash ≥4, zsh ใน ksh93 และ bash หากaเป็นอาร์เรย์ที่เชื่อมโยงแล้ว"${!a[@]}"จะเป็นอาร์เรย์ของคีย์:

for k in "${!a[@]}"; do
  echo "$k -> ${a[$k]}"
done

ใน zsh ไวยากรณ์นั้นทำงานในโหมดการจำลอง ksh เท่านั้น มิฉะนั้นคุณต้องใช้ไวยากรณ์ดั้งเดิมของ zsh:

for k in "${(@k)a}"; do
  echo "$k -> $a[$k]"
done

${(k)a}สามารถใช้งานได้หากaไม่มีคีย์ว่าง

ใน zsh คุณสามารถวนซ้ำทั้งkeys และvalues ​​ได้ในเวลาเดียวกัน:

for k v ("${(@kv)a}") echo "$k -> $v"

เชลล์ที่ไม่มีอาร์เรย์เชื่อมโยง

การเลียนแบบอาร์เรย์ที่เชื่อมโยงกันในเชลล์ที่ไม่มีพวกมันนั้นทำงานได้มากขึ้น หากคุณต้องการอาเรย์แบบเชื่อมโยงอาจถึงเวลาที่ต้องใช้เครื่องมือที่ใหญ่กว่าเช่น ksh93 หรือ Perl

หากคุณต้องการอาเรย์เชื่อมโยงในเชลล์ POSIX เพียงนี่คือวิธีในการจำลองเมื่อคีย์ถูก จำกัด ให้มีเพียงอักขระ0-9A-Z_a-z(ตัวเลข ASCII ตัวอักษรและขีดล่าง) ภายใต้สมมติฐานนี้คีย์สามารถใช้เป็นส่วนหนึ่งของชื่อตัวแปร ฟังก์ชั่นด้านล่างดำเนินการกับอาเรย์ที่ระบุโดยคำนำหน้าการตั้งชื่อ "ต้นกำเนิด" ซึ่งจะต้องไม่มีขีดล่างสองอันติดต่อกัน

## ainit STEM
## Declare an empty associative array named STEM.
ainit () {
  eval "__aa__${1}=' '"
}
## akeys STEM
## List the keys in the associatve array named STEM.
akeys () {
  eval "echo \"\$__aa__${1}\""
}
## aget STEM KEY VAR
## Set VAR to the value of KEY in the associative array named STEM.
## If KEY is not present, unset VAR.
aget () {
  eval "unset $3
        case \$__aa__${1} in
          *\" $2 \"*) $3=\$__aa__${1}__$2;;
        esac"
}
## aset STEM KEY VALUE
## Set KEY to VALUE in the associative array named STEM.
aset () {
  eval "__aa__${1}__${2}=\$3
        case \$__aa__${1} in
          *\" $2 \"*) :;;
          *) __aa__${1}=\"\${__aa__${1}}$2 \";;
        esac"
}
## aunset STEM KEY
## Remove KEY from the associative array named STEM.
aunset () {
  eval "unset __aa__${1}__${2}
        case \$__aa__${1} in
          *\" $2 \"*) __aa__${1}=\"\${__aa__${1}%%* $2 } \${__aa__${1}#* $2 }\";;
        esac"
}

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


5

ฉันไม่แน่ใจว่าคุณหมายถึงอะไรจากร้านค้า แต่คุณสามารถทำซ้ำปุ่มโดยใช้${!array[@]}ไวยากรณ์:

$ typeset -A foo=([key1]=bar [key2]=baz);
$ echo "${!foo[@]}" 
key2 key1

ดังนั้นเพื่อย้ำ:

$ for key in "${!foo[@]}"; do echo "$key : ${foo[$key]}"; done
key2 : baz
key1 : bar

ผมพบว่ามีความสุข, กวดวิชาสั้นเกี่ยวกับเรื่องนี้ที่นี่


ตามที่ระบุไว้ในความคิดเห็นด้านล่างอาร์เรย์เชื่อมโยงถูกเพิ่มเข้าไปในbashเวอร์ชัน 4 ดูที่นี่สำหรับบทความวารสาร Linux ในหัวข้อ


1
(bash version 4 only)นั่นเป็นสิ่งสำคัญที่ควรทราบ ตามเนื้อผ้าbashอาร์เรย์เป็นตัวเลขเท่านั้น
Ricky Beam

1
คุณอาจต้องการใช้typesetแทนdeclareตัวอย่างของคุณ ที่จะทำให้พวกมันพกพาได้ระหว่าง bash 4 และ ksh93 ซึ่งใช้อาร์เรย์เชื่อมโยงเชลล์เป็นครั้งแรก
jlliagre

0

เชลล์ที่ไม่มีอาร์เรย์เชื่อมโยง

มันไม่ได้ยากขนาดนั้นเมื่อปุ่มถูก จำกัด[0-9A-Za-z_](ตัวเลขตัวอักษรขีดเส้นใต้)

เคล็ดลับคือการจัดเก็บแทนการไปยังอาร์เรย์ [ $ คีย์ ] เก็บตัวแปร array_ $ สำคัญ

ตั้ง:

eval "array_$key='$value'"

จะได้รับ:

value=`eval echo '$'array_$key`

หมายเหตุ:ค่าต้องไม่มี'(เครื่องหมายคำพูดเดี่ยว)


-1

งานนี้ในทุบตี

cert="first"
web="second"
declare -A assoc_array=(["cert"]="${cert}" ["web"]="${web}")
echo "first is" ${assoc_array[cert]}
echo "second is" ${assoc_array[web]}

หรือ

#loop
for i in "${assoc_array[@]}"
do
   echo "$i"
done

ไม่จำเป็นต้องใช้ eval afaik


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