Array associativi negli script della shell


Risposte:


20

Per aggiungere alla risposta di Irfan , ecco una versione più breve e più veloce di get()poiché non richiede iterazione sui contenuti della mappa:

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

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

16
biforcare una subshell e sed è difficilmente ottimale. Bash4 lo supporta in modo nativo e bash3 ha alternative migliori.
lhunath

149

Un'altra opzione, se la portabilità non è la tua preoccupazione principale, è utilizzare array associativi incorporati nella shell. Questo dovrebbe funzionare in bash 4.0 (disponibile ora sulla maggior parte delle principali distribuzioni, anche se non su OS X a meno che non lo installi tu stesso), ksh e zsh:

declare -A newmap
newmap[name]="Irfan Zulfiqar"
newmap[designation]=SSE
newmap[company]="My Own Company"

echo ${newmap[company]}
echo ${newmap[name]}

A seconda della shell, potrebbe essere necessario fare un typeset -A newmapinvece di declare -A newmap, o in alcuni potrebbe non essere affatto necessario.


Grazie per aver postato la risposta, penso che sarebbe il modo migliore per farlo per i ragazzi che utilizzerebbero bash 4.0 o versioni successive.
Irfan Zulfiqar

Aggiungerei un po 'di confusione per assicurarmi che BASH_VERSION sia impostato e> = 4. E sì, BASH 4 è davvero, davvero fantastico!
Tim Post

Sto usando qualcosa di simile. Qual è il modo migliore per "rilevare" l'errore in cui l'array index / subscript non esiste? Ad esempio, cosa succede se stavo prendendo il pedice come opzione della riga di comando e l'utente ha fatto un errore di battitura e ha inserito "designatio"? Ricevo un errore di "indice dell'array errato" ma non come convalidare l'input al momento della ricerca dell'array, se possibile?
Ger

3
@ Jer È piuttosto oscuro, ma per determinare se una variabile è impostata nella shell, puoi usare test -z ${variable+x}( xnon importa, potrebbe essere qualsiasi stringa). Per un array associativo in Bash, puoi fare lo stesso; utilizzare test -z ${map[key]+x}.
Brian Campbell

95

Un altro modo 4 non bash.

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

Potresti anche lanciare un'istruzione if per cercare lì dentro. se [[$ var = ~ / blah /]]. o qualsiasi altra cosa.


2
Questo metodo è utile quando non hai effettivamente Bash 4. Ma penso che la riga che recupera il VALORE sarebbe più sicura in questo modo: VALUE = $ {animal # *:}. Con un solo carattere #, la corrispondenza si interromperà sul primo ":". Ciò consente anche ai valori di contenere ":".
Ced-le-pingouin

@ Ced-le-pingouin ~ Questo è un ottimo punto! Non l'ho capito. Ho modificato il mio post per riflettere i tuoi miglioramenti suggeriti.
Bubnoff

1
È un'emulazione piuttosto hacker di array associativi che utilizza la sostituzione dei parametri BASH. Il parametro "chiave" sostituisce tutto ciò che precede i due punti e il modello di valore sostituisce tutto ciò che è dopo i due punti. Simile a una corrispondenza con caratteri jolly regex. Quindi NON un vero array associativo. Non consigliato a meno che non sia necessario un modo facile da capire per eseguire funzionalità simili a array associativi / hash in BASH 3 o inferiore. Funziona però! Maggiori informazioni qui: tldp.org/LDP/abs/html/parameter-substitution.html#PSOREX2
Bubnoff

1
Questo non implementa un array associativo perché non fornisce un modo per cercare un elemento in base alla chiave. Fornisce solo un modo per trovare ogni chiave (e valore) da un indice numerico. (Un elemento può essere trovato per chiave iterando attraverso l'array, ma non è ciò che si desidera per un array associativo.)
Eric Postpischil

@EricPostpischil True. È solo un trucco. Consente a una persona di utilizzare la sintassi familiare nella configurazione, ma richiede comunque di iterare l'array come dici tu. Ho cercato di chiarire nel mio commento precedente che non è sicuramente un array associativo e non lo consiglio nemmeno se hai alternative. L'unico punto a suo favore, a mio avviso, è che è facile da scrivere e da usare per chi ha familiarità con altri linguaggi come Python. Se sei a un punto in cui vuoi effettivamente implementare array associativi in ​​BASH 3, potresti dover tornare un po 'sui tuoi passi.
Bubnoff

34

Penso che sia necessario fare un passo indietro e pensare a cosa sia veramente una mappa, o array associativo. È solo un modo per memorizzare un valore per una determinata chiave e recuperarlo in modo rapido ed efficiente. Potresti anche voler essere in grado di iterare sulle chiavi per recuperare ogni coppia di valori-chiave o eliminare le chiavi e i valori associati.

Ora, pensa a una struttura dati che usi sempre nello scripting della shell, e anche solo nella shell senza scrivere uno script, che abbia queste proprietà. Perplesso? È il filesystem.

In realtà, tutto ciò di cui hai bisogno per avere un array associativo nella programmazione della shell è una directory temporanea. mktemp -dè il tuo costruttore di array associativo:

prefix=$(basename -- "$0")
map=$(mktemp -dt ${prefix})
echo >${map}/key somevalue
value=$(cat ${map}/key)

Se non hai voglia di usare echoe cat, puoi sempre scrivere dei piccoli wrapper; questi sono modellati su quelli di Irfan, anche se restituiscono semplicemente il valore piuttosto che impostare variabili arbitrarie come $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

modifica : questo approccio è in realtà un po 'più veloce della ricerca lineare che utilizza sed suggerita dall'interrogante, oltre che più robusto (consente a chiavi e valori di contenere -, =, spazio, qnd ": SP:"). Il fatto che utilizzi il filesystem non lo rallenta; in realtà non è mai garantito che questi file vengano scritti sul disco a meno che non si chiami sync; per file temporanei come questo con una breve durata, non è improbabile che molti di essi non vengano mai scritti su disco.

Ho eseguito alcuni benchmark del codice di Irfan, la modifica di Jerry del codice di Irfan e il mio codice, utilizzando il seguente programma di driver:

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

I risultati:

    $ time ./driver.sh irfan 10 5

    0 m 0,975 s reali
    utente 0m0.280s
    sys 0m0.691s

    $ time ./driver.sh brian 10 5

    0 m 0,226 reali
    utente 0m0.057s
    sys 0m0.123s

    $ time ./driver.sh jerry 10 5

    0 m 0,706 s reali
    utente 0m0.228s
    sys 0m0.530s

    $ time ./driver.sh irfan 100 5

    0 m 10,633 reali
    utente 0m4.366s
    sys 0m7.127s

    $ time ./driver.sh brian 100 5

    0 m reali 1,682 s
    utente 0m0.546s
    sys 0m1.082s

    $ time ./driver.sh jerry 100 5

    0 m 9,315 reali
    utente 0m4.565s
    sys 0m5.446s

    $ time ./driver.sh irfan 10500

    1 m reale 46,197 s
    utente 0m44.869s
    sys 1m12.282s

    $ time ./driver.sh brian 10500

    0 m 16.003 reali
    utente 0m5.135s
    sys 0m10.396s

    $ time ./driver.sh jerry 10500

    1 m reale 24,414 s
    utente 0m39.696s
    sys 0m54.834s

    $ time ./driver.sh irfan 1000 5

    4 m reali 25,145 s
    utente 3m17.286s
    sys 1m21.490s

    $ time ./driver.sh brian 1000 5

    0 m 19,442 reali
    utente 0m5.287s
    sys 0m10.751s

    $ time ./driver.sh jerry 1000 5

    5 m reali 29,136 s
    utente 4m48.926s
    sys 0m59.336s


1
Non penso che dovresti usare il file system per le mappe, che fondamentalmente usa IO per qualcosa che puoi fare abbastanza velocemente in memoria.
Irfan Zulfiqar

9
I file non verranno necessariamente mai scritti sul disco; a meno che tu non chiami sincronizzazione, il sistema operativo potrebbe semplicemente lasciarli in memoria. Il tuo codice sta chiamando a sed ed esegue diverse ricerche lineari, che sono tutte molto lente. Ho fatto alcuni rapidi benchmark e la mia versione è 5-35 volte più veloce.
Brian Campbell

d'altra parte, gli array nativi di bash4 sono un approccio significativamente migliore e in bash3 puoi ancora tenere tutto fuori dal disco senza fork usando declare e indirection.
lhunath

7
"veloce" e "shell" non vanno comunque insieme: certamente non per il tipo di problemi di velocità di cui parliamo a livello di "evita minuscoli IO". È possibile cercare e utilizzare / dev / shm per garantire l'assenza di IO.
jmtd

2
Questa soluzione mi ha stupito ed è semplicemente fantastica. È ancora vero nel 2016. Dovrebbe davvero essere la risposta accettata.
Gordon

7

Bash4 lo supporta in modo nativo. Non usare grepo eval, sono gli hack più brutti.

Per una risposta dettagliata e dettagliata con codice di esempio, vedere: /programming/3467959


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; }'
}

Esempio:

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

Ora rispondo a questa domanda.

I seguenti script simulano array associativi negli script della shell. È semplice e molto facile da capire.

La mappa non è altro che una stringa infinita che ha keyValuePair salvato come --name = Irfan --designation = SSE --company = My: SP: Own: SP: Company

gli spazi sono sostituiti da ": SP:" per i valori

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

modifica: appena aggiunto un altro metodo per recuperare tutte le chiavi.

getKeySet() {
    if [ "$#" != 1 ]; 
    then 
        exit 1; 
    fi

    mapName=$1; 

    eval map="\"\$$mapName\""

    keySet=`
           echo $map | 
           sed -e "s/=[^ ]*//g" -e "s/\([ ]*\)--/\1/g"
          `
}

1
Stai importando evali dati come se fossero codice bash, e per di più: non riesci a citarli correttamente. Entrambi causano masse di bug e iniezione di codice arbitrario.
lhunath

3

Per Bash 3, c'è un caso particolare che ha una soluzione piacevole e semplice:

Se non vuoi gestire molte variabili o le chiavi sono semplicemente identificatori di variabili non validi e il tuo array è garantito per avere meno di 256 elementi , puoi abusare dei valori restituiti dalla funzione. Questa soluzione non richiede alcuna subshell in quanto il valore è prontamente disponibile come variabile, né alcuna iterazione in modo che le prestazioni urlano. Inoltre è molto leggibile, quasi come la versione Bash 4.

Ecco la versione più semplice:

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[$?]}

Ricorda, usa virgolette singole in case, altrimenti è soggetto a globbing. Veramente utile per hash statici / congelati dall'inizio, ma si potrebbe scrivere un generatore di indici da un filehash_keys=() array.

Attenzione, il valore predefinito è il primo, quindi potresti voler mettere da parte l'elemento zero:

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

Avvertenza: la lunghezza ora non è corretta.

In alternativa, se vuoi mantenere l'indicizzazione a base zero, puoi prenotare un altro valore di indice e proteggerti da una chiave inesistente, ma è meno leggibile:

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[$?]}

Oppure, per mantenere la lunghezza corretta, compensa l'indice di uno:

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

Puoi usare nomi di variabili dinamici e lasciare che i nomi delle variabili funzionino come le chiavi di una hashmap.

Ad esempio, se hai un file di input con due colonne, nome, credito, come nell'esempio qui sotto, e vuoi sommare il reddito di ogni utente:

Mary 100
John 200
Mary 50
John 300
Paul 100
Paul 400
David 100

Il comando seguente sommerà tutto, utilizzando variabili dinamiche come chiavi, sotto forma di map _ $ {person} :

while read -r person money; ((map_$person+=$money)); done < <(cat INCOME_REPORT.log)

Per leggere i risultati:

set | grep map

L'output sarà:

map_David=100
map_John=500
map_Mary=150
map_Paul=500

Elaborando queste tecniche, sto sviluppando su GitHub una funzione che funziona proprio come un oggetto HashMap , shell_map .

Per creare " istanze HashMap " la funzione shell_map è in grado di creare copie di se stessa con nomi diversi. Ogni nuova copia della funzione avrà una variabile $ FUNCNAME diversa. $ FUNCNAME viene quindi utilizzato per creare uno spazio dei nomi per ciascuna istanza di Map.

Le chiavi della mappa sono variabili globali, nella forma $ FUNCNAME_DATA_ $ KEY, dove $ KEY è la chiave aggiunta alla mappa. Queste variabili sono variabili dinamiche .

Di seguito ne metterò una versione semplificata in modo da poterla utilizzare come esempio.

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

Uso:

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

Ancora un altro modo non bash-4 (ovvero bash 3, compatibile con 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

stampe:

A1 => aaa
B2 => bbb
C3 => ccc
D4 => zzz

La funzione con caseagisce come un array associativo. Sfortunatamente non può usare return, quindi deve il echosuo output, ma questo non è un problema, a meno che tu non sia un purista che evita il fork delle subshell.


1

Peccato che non ho visto la domanda prima - ho scritto una libreria shell-framework che contiene tra le altre le mappe (array associativi). L'ultima versione può essere trovata qui .

Esempio:

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

Aggiungendo un'altra opzione, se jq è disponibile:

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

Ho trovato vero, come già accennato, che il metodo più performante è scrivere chiavi / vals in un file, quindi utilizzare grep / awk per recuperarli. Suona come ogni sorta di I / O non necessario, ma la cache del disco entra in gioco e lo rende estremamente efficiente, molto più velocemente rispetto al tentativo di memorizzarli in memoria usando uno dei metodi sopra (come mostrano i benchmark).

Ecco un metodo rapido e pulito che mi piace:

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`

Se si desidera applicare un valore singolo per chiave, è anche possibile eseguire una piccola azione grep / sed in hput ().


0

diversi anni fa ho scritto una libreria di script per bash che supportava array associativi tra le altre funzionalità (registrazione, file di configurazione, supporto esteso per argomenti della riga di comando, generazione di aiuto, test di unità, ecc.). La libreria contiene un wrapper per gli array associativi e passa automaticamente al modello appropriato (interno per bash4 ed emula per le versioni precedenti). Si chiamava shell-framework ed era ospitato su origo.ethz.ch ma oggi la risorsa è chiusa. Se qualcuno ne ha ancora bisogno, posso condividerlo con te.


Potrebbe valere la pena attaccarlo su GitHub
Mark K Cowan

0

Shell non ha una mappa incorporata come la struttura dei dati, uso una stringa grezza per descrivere elementi come questo:

ARRAY=(
    "item_A|attr1|attr2|attr3"
    "item_B|attr1|attr2|attr3"
    "..."
)

quando si estraggono elementi e i suoi attributi:

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

Questo sembra non intelligente rispetto alla risposta di altre persone, ma facile da capire per le nuove persone da sgusciare.


-1

Ho modificato la soluzione di Vadim con quanto segue:

####################################################################
# 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; }'
}

La modifica è map_get per evitare che restituisca errori se richiedi una chiave che non esiste, anche se l'effetto collaterale è che ignorerà anche silenziosamente le mappe mancanti, ma si adatta meglio al mio caso d'uso poiché ho appena voleva verificare la presenza di una chiave per saltare gli elementi in un ciclo.


-1

Risposta tardiva, ma considera di affrontare il problema in questo modo, usando il builtin bash letto come illustrato nello snippet di codice da uno script firewall ufw che segue. Questo approccio ha il vantaggio di utilizzare tutti i set di campi delimitati (non solo 2) desiderati. Abbiamo utilizzato | delimitatore perché gli specificatori dell'intervallo di porte possono richiedere i due punti, ad esempio 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.