มีวิธีที่ดีในการตรวจสอบว่าอาร์เรย์มีองค์ประกอบในทุบตี (ดีกว่าวนลูปผ่าน)?
อีกวิธีหนึ่งในการตรวจสอบว่าจำนวนหรือสตริงเท่ากับค่าคงที่ที่กำหนดไว้ล่วงหน้าหรือไม่?
มีวิธีที่ดีในการตรวจสอบว่าอาร์เรย์มีองค์ประกอบในทุบตี (ดีกว่าวนลูปผ่าน)?
อีกวิธีหนึ่งในการตรวจสอบว่าจำนวนหรือสตริงเท่ากับค่าคงที่ที่กำหนดไว้ล่วงหน้าหรือไม่?
คำตอบ:
ใน Bash 4 คุณสามารถใช้อาเรย์แบบเชื่อมโยง:
# set up array of constants
declare -A array
for constant in foo bar baz
do
array[$constant]=1
done
# test for existence
test1="bar"
test2="xyzzy"
if [[ ${array[$test1]} ]]; then echo "Exists"; fi # Exists
if [[ ${array[$test2]} ]]; then echo "Exists"; fi # doesn't
ในการตั้งค่าอาร์เรย์ในตอนแรกคุณสามารถทำการมอบหมายโดยตรงได้เช่นกัน:
array[foo]=1
array[bar]=1
# etc.
หรือด้วยวิธีนี้:
array=([foo]=1 [bar]=1 [baz]=1)
${array[$test1]}
ง่าย แต่มีปัญหา: มันจะไม่ทำงานถ้าคุณใช้set -u
ในสคริปต์ของคุณ (ซึ่งแนะนำ) เพราะคุณจะได้รับ "ตัวแปรไม่ได้ผูกไว้"
set -u
: davidpashley.com/articles/writing-robust-shell-scripts.html , blog.hashbang0.com/2010/05/18/robust-bash-scripts-part-one , openews.net/2012/bash- สคริปต์การเขียนที่แข็งแกร่ง
มันเป็นคำถามเก่า แต่ฉันคิดว่าวิธีแก้ปัญหาที่ง่ายที่สุดยังไม่ปรากฏ: test ${array[key]+_}
แต่ผมคิดว่าสิ่งที่เป็นทางออกที่ง่ายที่สุดไม่เคยปรากฏเลย: ตัวอย่าง:
declare -A xs=([a]=1 [b]="")
test ${xs[a]+_} && echo "a is set"
test ${xs[b]+_} && echo "b is set"
test ${xs[c]+_} && echo "c is set"
ขาออก:
a is set
b is set
env
เพื่อหลีกเลี่ยงความคลุมเครือในนามแฝง progs และฟังก์ชั่นอื่น ๆ ที่อาจใช้ชื่อ "test" env test ${xs[a]+_} && echo "a is set"
ดังกล่าวข้างต้น นอกจากนี้คุณยังสามารถรับฟังก์ชั่นนี้ได้โดยใช้วงเล็บสองตัวเคล็ดลับเดียวกันจากนั้นตรวจสอบค่าว่าง:[[ ! -z "${xs[b]+_}" ]] && echo "b is set"
[[ ${xs[b]+set} ]]
มีวิธีทดสอบว่าองค์ประกอบของอาร์เรย์ที่เชื่อมโยงมีอยู่ (ไม่ได้ตั้งค่า) ซึ่งแตกต่างจากที่ว่างเปล่า:
isNotSet() {
if [[ ! ${!1} && ${!1-_} ]]
then
return 1
fi
}
จากนั้นใช้:
declare -A assoc
KEY="key"
isNotSet assoc[${KEY}]
if [ $? -ne 0 ]
then
echo "${KEY} is not set."
fi
if ! some_check then return 1
some_check
ดังนั้น: isNotSet() { [[ ... ]] }
. ตรวจสอบวิธีการแก้ปัญหาของฉันด้านล่างคุณสามารถทำได้ง่ายๆ
คุณสามารถดูว่ามีรายการอยู่หรือไม่โดยการไพพ์เนื้อหาของอาร์เรย์ไปยัง grep
printf "%s\n" "${mydata[@]}" | grep "^${val}$"
นอกจากนี้คุณยังสามารถรับดัชนีของรายการด้วย grep -n ซึ่งส่งคืนหมายเลขบรรทัดของการแข่งขัน (อย่าลืมลบ 1 เพื่อรับดัชนี zero-based) ซึ่งจะรวดเร็วพอสมควรยกเว้นอาร์เรย์ที่มีขนาดใหญ่มาก
# given the following data
mydata=(a b c "hello world")
for val in a c hello "hello world"
do
# get line # of 1st matching entry
ix=$( printf "%s\n" "${mydata[@]}" | grep -n -m 1 "^${val}$" | cut -d ":" -f1 )
if [[ -z $ix ]]
then
echo $val missing
else
# subtract 1. Bash arrays are zero-based, but grep -n returns 1 for 1st line, not 0
echo $val found at $(( ix-1 ))
fi
done
a found at 0
c found at 2
hello missing
hello world found at 3
คำอธิบาย:
$( ... )
เหมือนกับการใช้ backticks เพื่อดักจับเอาต์พุตของคำสั่งลงในตัวแปร printf
เอาต์พุต mydata หนึ่งองค์ประกอบต่อบรรทัด @
แทนที่จะ*.
หลีกเลี่ยงการแยก "hello world" ออกเป็น 2 บรรทัด)grep
ค้นหาสตริงที่แน่นอน: ^
และ$
จับคู่การเริ่มต้นและท้ายบรรทัดgrep -n
ส่งคืนบรรทัด # ในรูปแบบ 4: hello world grep -m 1
ค้นหาคู่แรกเท่านั้นcut
แยกเพียงหมายเลขบรรทัด คุณสามารถพับการลบลงในคำสั่งได้ แต่ทดสอบ -1 สำหรับการขาดหายไป:
ix=$(( $( printf "%s\n" "${mydata[@]}" | grep -n -m 1 "^${val}$" | cut -d ":" -f1 ) - 1 ))
if [[ $ix == -1 ]]; then echo missing; else ... fi
$(( ... ))
คำนวณเลขจำนวนเต็มฉันไม่คิดว่าคุณสามารถทำได้อย่างถูกต้องโดยไม่ต้องวนลูปจนกว่าคุณจะมีข้อมูลที่ จำกัดมากในอาเรย์
นี่คือตัวแปรง่ายตัวหนึ่งที่บอกได้อย่างถูกต้องว่า"Super User"
มีอยู่ในอาร์เรย์ แต่มันก็ยังบอกว่า"uper Use"
อยู่ในอาเรย์
MyArray=('Super User' 'Stack Overflow' 'Server Fault' 'Jeff' );
FINDME="Super User"
FOUND=`echo ${MyArray[*]} | grep "$FINDME"`
if [ "${FOUND}" != "" ]; then
echo Array contains: $FINDME
else
echo $FINDME not found
fi
#
# If you where to add anchors < and > to the data it could work
# This would find "Super User" but not "uper Use"
#
MyArray2=('<Super User>' '<Stack Overflow>' '<Server Fault>' '<Jeff>' );
FOUND=`echo ${MyArray2[*]} | grep "<$FINDME>"`
if [ "${FOUND}" != "" ]; then
echo Array contains: $FINDME
else
echo $FINDME not found
fi
ปัญหาคือไม่มีวิธีง่าย ๆ ในการเพิ่มจุดยึด (ที่ฉันคิด) นอกเหนือจากการวนซ้ำผ่านอาร์เรย์ หากคุณไม่สามารถเพิ่มพวกเขาก่อนที่จะใส่ลงในอาร์เรย์ ...
grep "\b$FINDME\b"
) อาจจะทำงานกับค่าคงที่ไม่ใช่ตัวอักษรและตัวเลขที่ไม่มีช่องว่างด้วย"(^| )$FINDME(\$| )"
(หรือบางอย่างเช่นนั้น ... ฉันไม่เคยเรียนรู้สิ่งที่ grep grep ใช้ของ regexp)
#!/bin/bash
function in_array {
ARRAY=$2
for e in ${ARRAY[*]}
do
if [[ "$e" == "$1" ]]
then
return 0
fi
done
return 1
}
my_array=(Drupal Wordpress Joomla)
if in_array "Drupal" "${my_array[*]}"
then
echo "Found"
else
echo "Not found"
fi
in_array
ซึ่งเป็นสิ่งที่คุณกำลังทำอยู่ใน ไชโย
${ARRAY[@]}
จะใช้