คำชี้แจงสั้น ๆ ของคำถาม:
มีวิธีการทุบตีในตัวเพื่อนับจำนวนขององค์ประกอบในอาร์เรย์ทุบตีที่ชื่อของอาร์เรย์เป็นแบบไดนามิก (เช่นเก็บไว้ในตัวแปร) โดยไม่ต้องหันไปทำสำเนาอย่างเต็มที่ของอาร์เรย์หรือใช้eval
?
ข้อมูลมากกว่านี้:
การใช้การแทนที่พารามิเตอร์ bash สามารถทำได้ดังนี้:
myArr=(A B C); echo ${#myArr[@]}
กำหนดความยาวของอาร์เรย์:- การอ้างอิงตัวแปรทางอ้อมโดยใช้ชื่อ:
NAME=myVar; echo ${!NAME}
(สิ่งนี้ยังใช้กับองค์ประกอบอาร์เรย์):
NAME=myArr[1]; echo ${!NAME}
แต่ถ้าชื่อของอาเรย์ถูกเก็บไว้ในตัวแปรอีกตัวหนึ่งจะกำหนดจำนวนขององค์ประกอบในอาเรย์ได้อย่างไร? (หนึ่งอาจพิจารณาว่าเป็นการรวมกันของการแทนที่พารามิเตอร์สองตัวด้านบน) ตัวอย่างเช่น:
myArr=(A B C D)
NAME=myArr
# Get the number of elements in the array indirectly referenced by NAME.
count=${#$NAME[@]} # This syntax is invalid. What is the right way?
ด้านล่างนี้เป็นความพยายามหลายครั้งที่ FAIL ทั้งหมด:
# Setup for following attempts:
myArr=(A B C D)
NAME=myArr
EXPR1=$NAME[@] # i.e. EXPR1='myArr[@]'
EXPR2=#$NAME[@] # i.e. EXPR2='#myArr[@]'
# Failed attempts to get the lengh of the array indirectly:
1. count=${#$NAME[@]} # ERROR: bash: ...: bad substitution
2. count=${#!EXPR1} # ERROR: bash: !EXPR}: event not found
3. count=${#\!EXPR1} # ERROR: bash: ...: bad substitution
4. count=${!#EXPR1} # ERROR: bash: ...: bad substitution
5. count=${!EXPR2} # Returns NULL
ฉันได้พยายามยังมีบางสายพันธุ์อื่น ๆ ที่กล่าวมา แต่ยังไม่พบสิ่งใดที่ทำงานโดยทั้ง: (A) ทำสำเนาของอาร์เรย์หรือ (ข) eval
โดยใช้
วิธีการทำงาน:
มีสองวิธีในการแก้ปัญหานี้ซึ่งอาจไม่เหมาะสม (แต่แก้ไขให้ฉันถ้าฉันผิด):
วิธีที่ 1: คัดลอกแถวลำดับ
กำหนดอาเรย์ให้กับตัวแปรอื่น (ตั้งชื่อแบบสแตติก) และรับจำนวนขององค์ประกอบในนั้น
EXPR=$NAME[@]
arrCopy=( "${!EXPR}" )
count=${#arrCopy}
วิธีที่ 2: ใช้ eval
EXPR="count=\${#$NAME[@]}" # i.e. 'count=${myArr[@]}'
eval $EXPR
# Now count is set to the length of the array
สรุป:
มีวิธีการในตัว (เช่นการแทนที่พารามิเตอร์พารามิเตอร์) ในทุบตีเพื่อกำหนดความยาวของอาร์เรย์ทางอ้อม? ถ้าไม่วิธีที่มีประสิทธิภาพที่สุดในการทำเช่นนี้คืออะไร ฉันคิดว่ามันเป็นeval
วิธีการข้างต้น แต่มีปัญหาด้านความปลอดภัยหรือประสิทธิภาพการทำงานด้วยeval
หรือไม่
time bash -c 'a=(1 a +); c=a; for ((i=0;i<100000;i++)); do eval "echo \${#$c[@]}"; done' > /dev/null
และคล้ายกับe=$c[@]; d=("${!e}); echo ${#d[@]}
ในลูป Eval ใช้เวลาประมาณ 90% ในการคัดลอก และฉันคิดว่าช่องว่างนั้นจะเพิ่มเฉพาะอาเรย์และองค์ประกอบที่ใหญ่ขึ้นเท่านั้น