Асоціативні масиви в сценаріях Shell


Відповіді:


20

Щоб додати відповідь Ірфана , ось коротка та швидша версія, get()оскільки вона не потребує ітерації вмісту карти:

get() {
    mapName=$1; key=$2

    map=${!mapName}
    value="$(echo $map |sed -e "s/.*--${key}=\([^ ]*\).*/\1/" -e 's/:SP:/ /g' )"
}

16
роздвоєння нижньої оболонки і sed навряд чи оптимально. Bash4 підтримує це споконвічно, і bash3 має кращі альтернативи.
lhunath

149

Інший варіант, якщо портативність не є вашою основною проблемою, - використовувати асоціативні масиви, вбудовані в оболонку. Це має працювати в bash 4.0 (доступно зараз у більшості основних дистрибутивів, хоча не в 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, або в деяких може взагалі не знадобитися.


Дякую за те, що ви написали відповідь, я думаю, що це найкращий спосіб зробити це для хлопців, які будуть використовувати bash 4.0 або вище.
Ірфан Зульфікар

Я додаю трохи хитрості, щоб переконатися, що BASH_VERSION встановлений, і> = 4. І так, BASH 4 - це справді, дуже здорово!
Tim Post

Я використовую щось подібне. Який найкращий спосіб "зловити" помилку там, де індекс / індекс матриці не існує? Наприклад, що робити, якщо я брав підпис як варіант командного рядка, а користувач робив друкарську помилку і вводив "позначення"? Я отримую помилку "поганого підрозділу масиву", але не хочу, як перевірити вхід під час пошуку масиву, якщо це можливо?
Джер

3
@Jer Це досить незрозуміло, але щоб визначити, чи вказана змінна в оболонці, можна скористатися test -z ${variable+x}( xневажливо, що це може бути будь-який рядок). Для асоціативного масиву в Bash ви можете зробити подібне; використання test -z ${map[key]+x}.
Брайан Кемпбелл

95

Ще один невдалий 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 /]]. чи що завгодно.


2
Цей метод хороший, коли у вас справді немає Bash 4. Але я думаю, що рядок, який отримує VALUE, був би безпечнішим у такий спосіб: VALUE = $ {animal # *:}. За допомогою лише одного символу # відповідність зупиняється на першому ":". Це дозволяє також значенням містити ":".
Сед-ле-Пінгуін

@ Сед-ле-Пінгуін ~ Це чудовий момент! Я цього не спіймав. Я відредагував свою публікацію, щоб відобразити ваші запропоновані вдосконалення.
Bubnoff

1
Це досить шахрайська емуляція асоціативних масивів з використанням підстановки параметрів BASH. Параметр «ключ» замінює все перед двокрапкою, а шаблон значення замінює все після двокрапки. Аналогічно матчу підстановок з регулярними виразками Тож НЕ справжній асоціативний масив. Не рекомендується, якщо вам не потрібен простий для розуміння спосіб робити хеш / асоціативний масив, подібний до функцій BASH 3 або нижче. Це працює, хоча! Більше тут: tldp.org/LDP/abs/html/parameter-substitution.html#PSOREX2
Bubnoff

1
Це не реалізує асоціативний масив, оскільки він не забезпечує спосіб пошуку елемента за ключем. Він лише надає спосіб знайти кожен ключ (і значення) з числового індексу. (Елемент можна було знайти за ключем шляхом ітерації через масив, але це не те, що бажано для асоціативного масиву.)
Eric Postpischil

@EricPostpischil Правда. Це лише хак. Це дозволяє людині використовувати звичний синтаксис у налаштуваннях, але все ж вимагає повторення через масив, як ви говорите. У своєму попередньому коментарі я намагався бути зрозумілим, що це, безумовно, не асоціативний масив, і я навіть не рекомендую його, якщо у вас є альтернативи. На мій погляд, єдиний його користь полягає в тому, що це легко писати та використовувати для тих, хто знайомий з іншими мовами, такими як Python. Якщо ви знаходитесь в точці, де ви дійсно хочете реалізувати асоціативні масиви в BASH 3, можливо, вам доведеться трохи відбити свої кроки.
Bubnoff

34

Я думаю, що вам потрібно відступити і подумати про те, що насправді є карта чи асоціативний масив. Все це - спосіб зберегти значення для заданого ключа та повернути це значення швидко та ефективно. Ви також можете мати можливість перебирати ключі для отримання кожної пари значень ключів або видаляти ключі та пов’язані з ними значення.

Тепер подумайте про структуру даних, яку ви весь час використовуєте в сценаріях оболонок і навіть просто в оболонці, не написавши сценарій, що має ці властивості. Ступала? Це файлова система.

Дійсно, все, що вам потрібно мати асоціативний масив в програмуванні оболонок - це тимчасовий каталог. 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, запропонований запитувачем, а також більш надійний (він дозволяє клавішам і значенням містити -, =, пробіл, qnd ": SP:"). Той факт, що він використовує файлову систему, не робить це повільним; ці файли насправді ніколи не гарантовано записуються на диск, якщо ви не телефонуєтеsync ; для таких тимчасових файлів, які мають невеликий термін служби, малоймовірно, що багато з них ніколи не будуть записані на диск.

Я зробив кілька орієнтирів коду Ірфана, модифікації коду Ірфана Джеррі та мого коду, використовуючи наступну програму драйверів:

#!/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

Результати:

    $ час ./driver.sh irfan 10 5

    реальні 0м0,975с
    користувач 0m0.280s
    sys 0m0.691s

    $ час ./driver.sh Браян 10 5

    реальні 0м0.226с
    користувач 0m0.057s
    sys 0m0.123s

    $ time ./driver.sh jerry 10 5

    реальні 0м0.706с
    користувач 0m0.228s
    sys 0m0.530s

    $ час ./driver.sh irfan 100 5

    реальні 0м10.633с
    користувач 0m4.366s
    sys 0m7.127s

    $ час ./driver.sh Брайан 100 5

    реальні 0м1.682с
    користувач 0m0.546s
    sys 0m1.082s

    $ час ./driver.sh jerry 100 5

    реальні 0м9.315с
    користувач 0m4.565s
    sys 0m5.446s

    $ час ./driver.sh irfan 10 500

    справжній 1м46.197с
    користувач 0m44.869s
    sys 1m12.282s

    $ час ./driver.sh brian 10 500

    реальні 0м16.003с
    користувач 0m5.135s
    sys 0m10.396s

    $ час ./driver.sh jerry 10 500

    реальні 1м24.414с
    користувач 0m39.696s
    sys 0m54.834s

    $ час ./driver.sh irfan 1000 5

    справжні 4м25.145с
    користувач 3m17.286s
    sys 1m21.490s

    $ час ./driver.sh brian 1000 5

    реальні 0м19.442с
    користувач 0m5.287s
    sys 0m10.751s

    $ час ./driver.sh jerry 1000 5

    реальні 5м29.136с
    користувач 4m48.926s
    sys 0m59.336s


1
Я не думаю, що ви повинні використовувати файлову систему для карт, що в основному використовує IO для чогось, що ви можете зробити досить швидко в пам'яті.
Ірфан Зульфікар

9
Файли не обов'язково записуються на диск; якщо ви не викликаєте синхронізацію, операційна система може просто залишити їх у пам'яті. Ваш код викликає sed і виконує кілька лінійних пошуків, які все дуже повільно. Я зробив кілька швидких орієнтирів, і моя версія в 5-35 разів швидша.
Брайан Кемпбелл

з іншого боку, вбудовані масиви bash4 є значно кращим підходом, і в bash3 ви все одно можете тримати все з диска, не роздрібнюючись, використовуючи оголошення і непрямість.
lhunath

7
"швидкий" і "оболонка" насправді взагалі не йдуть разом: звичайно, не для таких питань щодо швидкості, про які ми говоримо на рівні "уникнути мізерного вводу". Ви можете шукати та використовувати / dev / shm, щоб гарантувати відсутність IO.
jmtd

2
Це рішення мене вразило, і просто приголомшливо. Все ще справедливо у 2016 році. Це дійсно має бути прийнятою відповіддю.
Гордон


7
####################################################################
# 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

4

Тепер відповідаємо на це питання.

Наступні сценарії імітують асоціативні масиви в скриптах оболонки. Його просто і дуже легко зрозуміти.

Карта - це не що інше, як нескінченний рядок, у якому збережений keyValuePair як --name = Irfan --designation = SSE --company = Мій: SP: Власний: 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"
          `
}

1
Ви даєте evalдані так, ніби це баш-код, і ще більше: ви не можете їх цитувати належним чином. Обидва викликають масу помилок і довільну ін'єкцію коду.
lhunath

3

Для Bash 3 є певний випадок, який має приємне та просте рішення:

Якщо ви не хочете обробляти багато змінних, або ключі просто недійсні ідентифікатори змінних, і ваш масив гарантовано матиме менше 256 елементів , ви можете зловживати функціями повернення значень. Це рішення не вимагає жодної додаткової оболонки, оскільки значення легко доступне у вигляді змінної, а також будь-якої ітерації, щоб продуктивність кричала. Крім того, це дуже легко читається, майже як версія 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=()масиву.

Слідкуйте за тим, що він за замовчуванням застосовується до першого, тому ви, можливо, захочете відкласти нульовий елемент:

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

Caveat: довжина зараз неправильна.

Крім того, якщо ви хочете зберегти нульову індексацію, ви можете зарезервувати інше значення індексу та захистити від неіснуючого ключа, але він менш читабельний:

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))]}

2

Ви можете використовувати імена динамічних змінних і дозволити ім'ям змінних працювати як ключі хешмапу.

Наприклад, якщо у вас є вхідний файл з двома стовпцями, ім'я, кредит, як наведено нижче, і ви хочете підсумовувати дохід кожного користувача:

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

Розвиваючи ці методи, я розробляю на GitHub функцію, яка працює так само, як HashMap Object , shell_map .

Для створення " екземплярів HashMap " функція shell_map здатна створювати копії себе під різними іменами. Кожна нова копія функції буде мати різну змінну $ FUNCNAME. $ FUNCNAME потім використовується для створення простору імен для кожного екземпляра Map.

Клавіші карти - це глобальні змінні у формі $ 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!"

2

Ще один не-bash-4 (тобто bash 3, сумісний з Mac):

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виводити, але це не проблема, якщо ви не пурист, який уникає розгортання передплатників.


1

Шкода, що я не бачив цього питання раніше - я написав оболонку бібліотеки, яка містить серед інших карти (асоціативні масиви). Останню його версію можна знайти тут .

Приклад:

#!/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")"

1

Додавання іншого параметра, якщо 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 '"' 

0

Як я вже згадував, я вважаю, що найкращим методом є виписати ключ / vals у файл, а потім використати grep / awk для їх отримання. Це звучить як усілякі непотрібні введення-виведення, але дисковий кеш запускається та робить його надзвичайно ефективним - набагато швидше, ніж намагатися зберігати їх у пам'яті за допомогою одного з перерахованих вище методів (як показують еталони).

Ось швидкий, чистий метод, який мені подобається:

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 ().


0

кілька років тому я написав бібліотеку сценаріїв для bash, яка підтримувала асоціативні масиви серед інших функцій (ведення журналів, файли конфігурації, розширена підтримка аргументу командного рядка, створення довідки, тестування одиниць тощо). Бібліотека містить обгортку для асоціативних масивів і автоматично переходить на відповідну модель (внутрішню для bash4 та емуляцію для попередніх версій). Він називався shell-frame і розміщувався на сайті origo.ethz.ch, але сьогодні ресурс закритий. Якщо комусь це все ще потрібно, я можу поділитися цим з вами.


Можливо, варто наклеїти його на github
Марк К Коуан

0

Shell не має вбудованої карти, як структура даних, я використовую необмежену рядок для опису таких елементів:

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

Це здається не розумним, ніж відповідь інших людей, але легким для розуміння для нових людей.


-1

Я змінив рішення Вадима таким чином:

####################################################################
# 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, щоб запобігти його поверненню помилок, якщо ви вимагаєте ключ, який не існує, хоча побічний ефект полягає в тому, що він також мовчки ігнорує відсутні карти, але він краще підходить для мого використання, оскільки я просто хотів перевірити ключ, щоб пропустити елементи в циклі.


-1

Пізня відповідь, але розглядайте проблему таким чином, використовуючи вбудований bash, прочитаний, як показано у фрагменті коду із сценарію брандмауера ufw, який випливає нижче. Цей підхід має перевагу у використанні стільки розмежованих наборів полів (не лише 2), скільки бажано. Ми використали | роздільник, оскільки специфікатори діапазону портів можуть вимагати двокрапки, тобто 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.