เราต้องการสคริปต์ที่จำลอง Associative arrays หรือ Map เช่นโครงสร้างข้อมูลสำหรับ Shell Scripting เนื้อหาใด ๆ ?
เราต้องการสคริปต์ที่จำลอง Associative arrays หรือ Map เช่นโครงสร้างข้อมูลสำหรับ Shell Scripting เนื้อหาใด ๆ ?
คำตอบ:
หากต้องการเพิ่มคำตอบของ Irfanนี่เป็นเวอร์ชันที่สั้นกว่าและเร็วกว่าget()
เนื่องจากไม่ต้องทำซ้ำในเนื้อหาแผนที่:
get() {
mapName=$1; key=$2
map=${!mapName}
value="$(echo $map |sed -e "s/.*--${key}=\([^ ]*\).*/\1/" -e 's/:SP:/ /g' )"
}
อีกทางเลือกหนึ่งหากการพกพาไม่ใช่ข้อกังวลหลักของคุณคือการใช้อาร์เรย์เชื่อมโยงที่ติดตั้งในเชลล์ สิ่งนี้ควรใช้งานได้ใน bash 4.0 (พร้อมใช้งานแล้วใน distros หลัก ๆ ส่วนใหญ่แม้ว่าจะไม่ใช่ใน OS X เว้นแต่คุณจะติดตั้งด้วยตัวเอง), ksh และ zsh:
declare -A newmap
newmap[name]="Irfan Zulfiqar"
newmap[designation]=SSE
newmap[company]="My Own Company"
echo ${newmap[company]}
echo ${newmap[name]}
ขึ้นอยู่กับเปลือกคุณอาจต้องทำtypeset -A newmap
แทนdeclare -A newmap
หรือในบางกรณีอาจไม่จำเป็นเลย
test -z ${variable+x}
( x
ไม่สำคัญนั่นอาจเป็นสตริงใดก็ได้) สำหรับอาร์เรย์ที่เชื่อมโยงใน Bash คุณสามารถทำได้เช่นเดียวกัน ใช้test -z ${map[key]+x}
.
อีกวิธีที่ไม่ทุบตี 4
#!/bin/bash
# A pretend Python dictionary with bash 3
ARRAY=( "cow:moo"
"dinosaur:roar"
"bird:chirp"
"bash:rock" )
for animal in "${ARRAY[@]}" ; do
KEY=${animal%%:*}
VALUE=${animal#*:}
printf "%s likes to %s.\n" "$KEY" "$VALUE"
done
echo -e "${ARRAY[1]%%:*} is an extinct animal which likes to ${ARRAY[1]#*:}\n"
คุณสามารถใส่คำสั่ง if เพื่อค้นหาในนั้นได้เช่นกัน ถ้า [[$ var = ~ / blah /]] หรืออะไรก็ตาม
ฉันคิดว่าคุณต้องย้อนกลับไปและคิดว่าจริงๆแล้วแผนที่หรืออาร์เรย์แบบเชื่อมโยงคืออะไร ทั้งหมดนี้เป็นวิธีการจัดเก็บค่าสำหรับคีย์หนึ่ง ๆ และรับมูลค่านั้นกลับคืนมาอย่างรวดเร็วและมีประสิทธิภาพ คุณอาจต้องการที่จะสามารถทำซ้ำบนคีย์เพื่อดึงทุกคู่ค่าคีย์หรือลบคีย์และค่าที่เกี่ยวข้อง
ตอนนี้ให้นึกถึงโครงสร้างข้อมูลที่คุณใช้ตลอดเวลาในเชลล์สคริปต์และแม้แต่ในเชลล์โดยไม่ต้องเขียนสคริปต์ก็มีคุณสมบัติเหล่านี้ นิ่งงัน? มันคือระบบไฟล์
จริงๆแล้วสิ่งที่คุณต้องมีในอาร์เรย์ที่เชื่อมโยงในการเขียนโปรแกรมเชลล์คือไดเร็กทอรีชั่วคราว mktemp -d
เป็นตัวสร้างอาร์เรย์ที่เชื่อมโยงของคุณ:
prefix=$(basename -- "$0")
map=$(mktemp -dt ${prefix})
echo >${map}/key somevalue
value=$(cat ${map}/key)
หากคุณไม่ต้องการใช้echo
และcat
คุณสามารถเขียนกระดาษห่อเล็ก ๆ ได้ตลอดเวลา สิ่งเหล่านี้จำลองมาจาก Irfan แม้ว่าพวกเขาจะส่งออกค่าแทนที่จะตั้งค่าตัวแปรตามอำเภอใจเช่น$value
:
#!/bin/sh
prefix=$(basename -- "$0")
mapdir=$(mktemp -dt ${prefix})
trap 'rm -r ${mapdir}' EXIT
put() {
[ "$#" != 3 ] && exit 1
mapname=$1; key=$2; value=$3
[ -d "${mapdir}/${mapname}" ] || mkdir "${mapdir}/${mapname}"
echo $value >"${mapdir}/${mapname}/${key}"
}
get() {
[ "$#" != 2 ] && exit 1
mapname=$1; key=$2
cat "${mapdir}/${mapname}/${key}"
}
put "newMap" "name" "Irfan Zulfiqar"
put "newMap" "designation" "SSE"
put "newMap" "company" "My Own Company"
value=$(get "newMap" "company")
echo $value
value=$(get "newMap" "name")
echo $value
แก้ไข : วิธีนี้ค่อนข้างเร็วกว่าการค้นหาเชิงเส้นโดยใช้ sed ที่ผู้ถามแนะนำและมีประสิทธิภาพมากกว่า (ช่วยให้คีย์และค่ามี -, =, space, qnd ": SP:") ความจริงที่ว่ามันใช้ระบบไฟล์ไม่ได้ทำให้มันช้า ไฟล์เหล่านี้ไม่รับประกันว่าจะถูกเขียนลงดิสก์เว้นแต่คุณจะโทรsync
; สำหรับไฟล์ชั่วคราวแบบนี้ที่มีอายุการใช้งานสั้นไม่น่าเป็นไปได้ที่ไฟล์เหล่านี้จะไม่ถูกเขียนลงดิสก์
ฉันทำเกณฑ์มาตรฐานของรหัสของ Irfan การปรับเปลี่ยนรหัสของ Irfan และรหัสของ Jerry โดยใช้โปรแกรมไดรเวอร์ต่อไปนี้:
#!/bin/sh
mapimpl=$1
numkeys=$2
numvals=$3
. ./${mapimpl}.sh #/ <- fix broken stack overflow syntax highlighting
for (( i = 0 ; $i < $numkeys ; i += 1 ))
do
for (( j = 0 ; $j < $numvals ; j += 1 ))
do
put "newMap" "key$i" "value$j"
get "newMap" "key$i"
done
done
ผลลัพธ์:
$ time ./driver.sh irfan 10 5 0m0.975s จริง ผู้ใช้ 0m0.280s sys 0m0.691s $ time ./driver.sh ไบรอัน 10 5 0m0.226s จริง ผู้ใช้ 0m0.057s sys 0m0.123s $ time ./driver.sh เจอร์รี่ 10 5 0m0.706s จริง ผู้ใช้ 0m0.228s sys 0m0.530s $ time ./driver.sh irfan 100 5 0m10.633s จริง ผู้ใช้ 0m4.366s sys 0m7.127s $ time ./driver.sh ไบรอัน 100 5 0m1.682s จริง ผู้ใช้ 0m0.546s sys 0m1.082s $ time ./driver.sh เจอร์รี่ 100 5 จริง 0m9.315s ผู้ใช้ 0m4.565s sys 0m5.446s $ time ./driver.sh irfan 10500 1m46.197s จริง ผู้ใช้ 0m44.869s sys 1m12.282s $ time ./driver.sh ไบรอัน 10500 0m16.003s จริง ผู้ใช้ 0m5.135s sys 0m10.396s $ time ./driver.sh เจอร์รี่ 10500 1m24.414s จริง ผู้ใช้ 0m39.696s sys 0m54.834s $ time ./driver.sh irfan 1000 5 4m25.145s จริง ผู้ใช้ 3m17.286s sys 1m21.490s $ time ./driver.sh ไบรอัน 1000 5 0m19.442s จริง ผู้ใช้ 0m5.287s sys 0m10.751s $ time ./driver.sh เจอร์รี่ 1000 5 5 นาที 29.136 วินาทีจริง ผู้ใช้ 4m48.926s sys 0m59.336s
Bash4 รองรับสิ่งนี้โดยกำเนิด อย่าใช้grep
หรือeval
เป็นแฮ็กที่น่าเกลียดที่สุด
สำหรับคำตอบโดยละเอียดพร้อมรหัสตัวอย่างโปรดดู: /programming/3467959
####################################################################
# Bash v3 does not support associative arrays
# and we cannot use ksh since all generic scripts are on bash
# Usage: map_put map_name key value
#
function map_put
{
alias "${1}$2"="$3"
}
# map_get map_name key
# @return value
#
function map_get
{
alias "${1}$2" | awk -F"'" '{ print $2; }'
}
# map_keys map_name
# @return map keys
#
function map_keys
{
alias -p | grep $1 | cut -d'=' -f1 | awk -F"$1" '{print $2; }'
}
ตัวอย่าง:
mapName=$(basename $0)_map_
map_put $mapName "name" "Irfan Zulfiqar"
map_put $mapName "designation" "SSE"
for key in $(map_keys $mapName)
do
echo "$key = $(map_get $mapName $key)
done
ตอนนี้กำลังตอบคำถามนี้
สคริปต์ต่อไปนี้จำลองอาร์เรย์ที่เชื่อมโยงในเชลล์สคริปต์ มันง่ายและเข้าใจง่ายมาก
แผนที่ไม่มีอะไรนอกจากสตริงที่ไม่มีวันสิ้นสุดที่มี keyValuePair บันทึกเป็น --name = Irfan --designation = SSE --company = My: SP: Own: SP: Company
ช่องว่างจะถูกแทนที่ด้วย ': SP:' สำหรับค่า
put() {
if [ "$#" != 3 ]; then exit 1; fi
mapName=$1; key=$2; value=`echo $3 | sed -e "s/ /:SP:/g"`
eval map="\"\$$mapName\""
map="`echo "$map" | sed -e "s/--$key=[^ ]*//g"` --$key=$value"
eval $mapName="\"$map\""
}
get() {
mapName=$1; key=$2; valueFound="false"
eval map=\$$mapName
for keyValuePair in ${map};
do
case "$keyValuePair" in
--$key=*) value=`echo "$keyValuePair" | sed -e 's/^[^=]*=//'`
valueFound="true"
esac
if [ "$valueFound" == "true" ]; then break; fi
done
value=`echo $value | sed -e "s/:SP:/ /g"`
}
put "newMap" "name" "Irfan Zulfiqar"
put "newMap" "designation" "SSE"
put "newMap" "company" "My Own Company"
get "newMap" "company"
echo $value
get "newMap" "name"
echo $value
แก้ไข:เพิ่งเพิ่มวิธีอื่นในการดึงคีย์ทั้งหมด
getKeySet() {
if [ "$#" != 1 ];
then
exit 1;
fi
mapName=$1;
eval map="\"\$$mapName\""
keySet=`
echo $map |
sed -e "s/=[^ ]*//g" -e "s/\([ ]*\)--/\1/g"
`
}
eval
ข้อมูลราวกับว่าเป็นรหัสทุบตีและยิ่งไปกว่านั้น: คุณไม่ได้อ้างอย่างถูกต้อง ทั้งสองทำให้เกิดข้อบกพร่องจำนวนมากและการฉีดรหัสโดยพลการ
สำหรับ Bash 3 มีบางกรณีที่มีวิธีแก้ปัญหาที่ดีและเรียบง่าย:
หากคุณไม่ต้องการจัดการกับตัวแปรจำนวนมากหรือคีย์เป็นเพียงตัวระบุตัวแปรที่ไม่ถูกต้องและอาร์เรย์ของคุณได้รับการรับรองว่ามีรายการน้อยกว่า 256 รายการคุณสามารถละเมิดฟังก์ชันการส่งคืนค่าได้ โซลูชันนี้ไม่จำเป็นต้องใช้ subshell ใด ๆ เนื่องจากค่าพร้อมใช้งานเป็นตัวแปรหรือการวนซ้ำใด ๆ เพื่อให้ประสิทธิภาพการทำงานดังขึ้น นอกจากนี้ยังสามารถอ่านได้เกือบจะเหมือนกับเวอร์ชัน Bash 4
นี่คือเวอร์ชันพื้นฐานที่สุด:
hash_index() {
case $1 in
'foo') return 0;;
'bar') return 1;;
'baz') return 2;;
esac
}
hash_vals=("foo_val"
"bar_val"
"baz_val");
hash_index "foo"
echo ${hash_vals[$?]}
โปรดจำไว้ว่าให้ใช้เครื่องหมายคำพูดเดี่ยวในcase
มิฉะนั้นอาจมีการปัดเศษ มีประโยชน์มากสำหรับแฮชแบบคงที่ / แช่แข็งตั้งแต่เริ่มต้น แต่เราสามารถเขียนตัวสร้างดัชนีจากhash_keys=()
อาร์เรย์ได้
ระวังมันเป็นค่าเริ่มต้นขององค์ประกอบแรกดังนั้นคุณอาจต้องการแยกองค์ประกอบ zeroth:
hash_index() {
case $1 in
'foo') return 1;;
'bar') return 2;;
'baz') return 3;;
esac
}
hash_vals=("", # sort of like returning null/nil for a non existent key
"foo_val"
"bar_val"
"baz_val");
hash_index "foo" || echo ${hash_vals[$?]} # It can't get more readable than this
ข้อแม้: ตอนนี้ความยาวไม่ถูกต้อง
หรือหากคุณต้องการคงการจัดทำดัชนีแบบศูนย์ไว้คุณสามารถสงวนค่าดัชนีอื่นและป้องกันคีย์ที่ไม่มีอยู่จริง แต่อ่านได้น้อยลง:
hash_index() {
case $1 in
'foo') return 0;;
'bar') return 1;;
'baz') return 2;;
*) return 255;;
esac
}
hash_vals=("foo_val"
"bar_val"
"baz_val");
hash_index "foo"
[[ $? -ne 255 ]] && echo ${hash_vals[$?]}
หรือเพื่อให้ความยาวถูกต้องให้หักล้างดัชนีทีละรายการ:
hash_index() {
case $1 in
'foo') return 1;;
'bar') return 2;;
'baz') return 3;;
esac
}
hash_vals=("foo_val"
"bar_val"
"baz_val");
hash_index "foo" || echo ${hash_vals[$(($? - 1))]}
คุณสามารถใช้ชื่อตัวแปรแบบไดนามิกและปล่อยให้ชื่อตัวแปรทำงานเหมือนคีย์ของแฮชแมป
ตัวอย่างเช่นหากคุณมีไฟล์อินพุตที่มีสองคอลัมน์ชื่อเครดิตดังตัวอย่างการร้องและคุณต้องการรวมรายได้ของผู้ใช้แต่ละคน:
Mary 100
John 200
Mary 50
John 300
Paul 100
Paul 400
David 100
การร้องคำสั่งจะรวมทุกอย่างโดยใช้ตัวแปรแบบไดนามิกเป็นคีย์ในรูปแบบของแผนที่ _ $ {person} :
while read -r person money; ((map_$person+=$money)); done < <(cat INCOME_REPORT.log)
หากต้องการอ่านผลลัพธ์:
set | grep map
ผลลัพธ์จะเป็น:
map_David=100
map_John=500
map_Mary=150
map_Paul=500
Elaborating เกี่ยวกับเทคนิคเหล่านี้ผมกำลังพัฒนาบน GitHub ฟังก์ชั่นที่ใช้งานได้เช่นเดียวกับที่HashMap วัตถุ , shell_map
ในการสร้าง " อินสแตนซ์ HashMap " ฟังก์ชัน shell_mapสามารถสร้างสำเนาของตัวเองภายใต้ชื่อที่แตกต่างกัน สำเนาฟังก์ชันใหม่แต่ละรายการจะมีตัวแปร $ FUNCNAME ที่แตกต่างกัน จากนั้น $ FUNCNAME จะใช้เพื่อสร้างเนมสเปซสำหรับแต่ละอินสแตนซ์แผนที่
คีย์แผนที่เป็นตัวแปรส่วนกลางในรูปแบบ $ FUNCNAME_DATA_ $ KEY โดยที่ $ KEY เป็นคีย์ที่เพิ่มลงในแผนที่ ตัวแปรเหล่านี้เป็นตัวแปรแบบไดนามิก
ร้องฉันจะใส่เวอร์ชันที่เรียบง่ายเพื่อให้คุณสามารถใช้เป็นตัวอย่างได้
#!/bin/bash
shell_map () {
local METHOD="$1"
case $METHOD in
new)
local NEW_MAP="$2"
# loads shell_map function declaration
test -n "$(declare -f shell_map)" || return
# declares in the Global Scope a copy of shell_map, under a new name.
eval "${_/shell_map/$2}"
;;
put)
local KEY="$2"
local VALUE="$3"
# declares a variable in the global scope
eval ${FUNCNAME}_DATA_${KEY}='$VALUE'
;;
get)
local KEY="$2"
local VALUE="${FUNCNAME}_DATA_${KEY}"
echo "${!VALUE}"
;;
keys)
declare | grep -Po "(?<=${FUNCNAME}_DATA_)\w+((?=\=))"
;;
name)
echo $FUNCNAME
;;
contains_key)
local KEY="$2"
compgen -v ${FUNCNAME}_DATA_${KEY} > /dev/null && return 0 || return 1
;;
clear_all)
while read var; do
unset $var
done < <(compgen -v ${FUNCNAME}_DATA_)
;;
remove)
local KEY="$2"
unset ${FUNCNAME}_DATA_${KEY}
;;
size)
compgen -v ${FUNCNAME}_DATA_${KEY} | wc -l
;;
*)
echo "unsupported operation '$1'."
return 1
;;
esac
}
การใช้งาน:
shell_map new credit
credit put Mary 100
credit put John 200
for customer in `credit keys`; do
value=`credit get $customer`
echo "customer $customer has $value"
done
credit contains_key "Mary" && echo "Mary has credit!"
อีกวิธีหนึ่งที่ไม่ใช่ bash-4 (เช่น bash 3, Mac-compatible):
val_of_key() {
case $1 in
'A1') echo 'aaa';;
'B2') echo 'bbb';;
'C3') echo 'ccc';;
*) echo 'zzz';;
esac
}
for x in 'A1' 'B2' 'C3' 'D4'; do
y=$(val_of_key "$x")
echo "$x => $y"
done
พิมพ์:
A1 => aaa
B2 => bbb
C3 => ccc
D4 => zzz
ฟังก์ชันที่มีการcase
กระทำเหมือนอาร์เรย์เชื่อมโยง น่าเสียดายที่ไม่สามารถใช้งานได้return
ดังนั้นจึงต้องมีecho
เอาต์พุต แต่นี่ไม่ใช่ปัญหาเว้นแต่คุณจะเป็นคนเจ้าระเบียบที่หลีกเลี่ยงการฟอร์ก subshells
สิ่งที่น่าเสียดายที่ฉันไม่เห็นคำถามมาก่อน - ฉันได้เขียนเชลล์เฟรมเวิร์กของไลบรารีซึ่งมีแผนที่ (อาร์เรย์ที่เกี่ยวข้อง) รุ่นสุดท้ายของมันสามารถพบได้ที่นี่
ตัวอย่าง:
#!/bin/bash
#include map library
shF_PATH_TO_LIB="/usr/lib/shell-framework"
source "${shF_PATH_TO_LIB}/map"
#simple example get/put
putMapValue "mapName" "mapKey1" "map Value 2"
echo "mapName[mapKey1]: $(getMapValue "mapName" "mapKey1")"
#redefine old value to new
putMapValue "mapName" "mapKey1" "map Value 1"
echo "after change mapName[mapKey1]: $(getMapValue "mapName" "mapKey1")"
#add two new pairs key/values and print all keys
putMapValue "mapName" "mapKey2" "map Value 2"
putMapValue "mapName" "mapKey3" "map Value 3"
echo -e "mapName keys are \n$(getMapKeys "mapName")"
#create new map
putMapValue "subMapName" "subMapKey1" "sub map Value 1"
putMapValue "subMapName" "subMapKey2" "sub map Value 2"
#and put it in mapName under key "mapKey4"
putMapValue "mapName" "mapKey4" "subMapName"
#check if under two key were placed maps
echo "is map mapName[mapKey3]? - $(if isMap "$(getMapValue "mapName" "mapKey3")" ; then echo Yes; else echo No; fi)"
echo "is map mapName[mapKey4]? - $(if isMap "$(getMapValue "mapName" "mapKey4")" ; then echo Yes; else echo No; fi)"
#print map with sub maps
printf "%s\n" "$(mapToString "mapName")"
การเพิ่มตัวเลือกอื่นถ้า jq พร้อมใช้งาน:
export NAMES="{
\"Mary\":\"100\",
\"John\":\"200\",
\"Mary\":\"50\",
\"John\":\"300\",
\"Paul\":\"100\",
\"Paul\":\"400\",
\"David\":\"100\"
}"
export NAME=David
echo $NAMES | jq --arg v "$NAME" '.[$v]' | tr -d '"'
ฉันพบว่ามันเป็นความจริงดังที่ได้กล่าวไปแล้วว่าวิธีที่มีประสิทธิภาพดีที่สุดคือการเขียนคีย์ / vals ลงในไฟล์จากนั้นใช้ grep / awk เพื่อดึงข้อมูล ดูเหมือนว่า IO ที่ไม่จำเป็นทุกประเภท แต่แคชของดิสก์จะเริ่มทำงานและทำให้มีประสิทธิภาพสูง - เร็วกว่าการพยายามจัดเก็บไว้ในหน่วยความจำโดยใช้วิธีใดวิธีหนึ่งข้างต้น (ดังที่แสดงในเกณฑ์มาตรฐาน)
นี่เป็นวิธีที่รวดเร็วและสะอาดที่ฉันชอบ:
hinit() {
rm -f /tmp/hashmap.$1
}
hput() {
echo "$2 $3" >> /tmp/hashmap.$1
}
hget() {
grep "^$2 " /tmp/hashmap.$1 | awk '{ print $2 };'
}
hinit capitols
hput capitols France Paris
hput capitols Netherlands Amsterdam
hput capitols Spain Madrid
echo `hget capitols France` and `hget capitols Netherlands` and `hget capitols Spain`
หากคุณต้องการบังคับใช้ค่าเดียวต่อคีย์คุณสามารถดำเนินการ grep / sed เล็กน้อยใน hput () ได้
หลายปีก่อนฉันเขียนไลบรารีสคริปต์สำหรับ bash ซึ่งสนับสนุนอาร์เรย์ที่เชื่อมโยงระหว่างคุณสมบัติอื่น ๆ (การบันทึกไฟล์การกำหนดค่าการสนับสนุนเพิ่มเติมสำหรับอาร์กิวเมนต์บรรทัดคำสั่งสร้างวิธีใช้การทดสอบหน่วย ฯลฯ ) ไลบรารีมีตัวห่อสำหรับอาร์เรย์ที่เชื่อมโยงและเปลี่ยนเป็นโมเดลที่เหมาะสมโดยอัตโนมัติ (ภายในสำหรับ bash4 และจำลองสำหรับเวอร์ชันก่อนหน้า) ถูกเรียกว่าเชลล์เฟรมเวิร์กและโฮสต์ที่ origo.ethz.ch แต่วันนี้ทรัพยากรถูกปิด หากยังมีคนต้องการฉันสามารถแบ่งปันกับคุณได้
เชลล์ไม่มีแผนที่ในตัวเช่นโครงสร้างข้อมูลฉันใช้สตริงดิบเพื่ออธิบายรายการเช่นนั้น:
ARRAY=(
"item_A|attr1|attr2|attr3"
"item_B|attr1|attr2|attr3"
"..."
)
เมื่อแยกไอเท็มและคุณสมบัติ:
for item in "${ARRAY[@]}"
do
item_name=$(echo "${item}"|awk -F "|" '{print $1}')
item_attr1=$(echo "${item}"|awk -F "|" '{print $2}')
item_attr2=$(echo "${item}"|awk -F "|" '{print $3}')
echo "${item_name}"
echo "${item_attr1}"
echo "${item_attr2}"
done
ดูเหมือนจะไม่ฉลาดไปกว่าคำตอบของคนอื่น แต่เข้าใจง่ายสำหรับคนใหม่ ๆ
ฉันแก้ไขโซลูชันของ Vadim ด้วยสิ่งต่อไปนี้:
####################################################################
# Bash v3 does not support associative arrays
# and we cannot use ksh since all generic scripts are on bash
# Usage: map_put map_name key value
#
function map_put
{
alias "${1}$2"="$3"
}
# map_get map_name key
# @return value
#
function map_get {
if type -p "${1}$2"
then
alias "${1}$2" | awk -F "'" '{ print $2; }';
fi
}
# map_keys map_name
# @return map keys
#
function map_keys
{
alias -p | grep $1 | cut -d'=' -f1 | awk -F"$1" '{print $2; }'
}
การเปลี่ยนแปลงคือ map_get เพื่อป้องกันไม่ให้ส่งคืนข้อผิดพลาดหากคุณขอคีย์ที่ไม่มีอยู่แม้ว่าผลข้างเคียงคือมันจะเพิกเฉยต่อแผนที่ที่หายไป แต่มันก็เหมาะกับกรณีการใช้งานของฉันดีกว่าเนื่องจากฉันเพิ่ง ต้องการตรวจสอบคีย์เพื่อข้ามรายการแบบวนซ้ำ
การตอบกลับช้า แต่ให้พิจารณาแก้ไขปัญหาด้วยวิธีนี้โดยใช้ bash builtin อ่านตามภาพประกอบในส่วนโค้ดจากสคริปต์ไฟร์วอลล์ ufw ที่ตามมา วิธีนี้มีข้อได้เปรียบในการใช้ชุดเขตข้อมูลที่คั่น (ไม่ใช่แค่ 2) ตามที่ต้องการ เราได้ใช้| คั่นเพราะ specifiers ช่วงพอร์ตอาจต้องลำไส้ใหญ่เช่น6001: 6010
#!/usr/bin/env bash
readonly connections=(
'192.168.1.4/24|tcp|22'
'192.168.1.4/24|tcp|53'
'192.168.1.4/24|tcp|80'
'192.168.1.4/24|tcp|139'
'192.168.1.4/24|tcp|443'
'192.168.1.4/24|tcp|445'
'192.168.1.4/24|tcp|631'
'192.168.1.4/24|tcp|5901'
'192.168.1.4/24|tcp|6566'
)
function set_connections(){
local range proto port
for fields in ${connections[@]}
do
IFS=$'|' read -r range proto port <<< "$fields"
ufw allow from "$range" proto "$proto" to any port "$port"
done
}
set_connections