823 Stimmen

Wie definiert man Hash-Tabellen in der Bash?

Was ist das Äquivalent von Python-Wörterbücher sondern in Bash (sollte unter OS X und Linux funktionieren).

6 Stimmen

Bash soll ein Python/Perl-Skript ausführen... Das ist so viel flexibler!

1 Stimmen

3voto

jrichard Punkte 31

Zwei Dinge: Sie können Speicher anstelle von /tmp in jedem Kernel 2.6 verwenden, indem Sie /dev/shm (Redhat) benutzen, andere Distributionen können abweichen. Außerdem kann hget mit read wie folgt neu implementiert werden:

function hget {

  while read key idx
  do
    if [ $key = $2 ]
    then
      echo $idx
      return
    fi
  done < /dev/shm/hashmap.$1
}

Durch die Annahme, dass alle Schlüssel eindeutig sind, schließt die Rückgabe die Leseschleife kurz und verhindert, dass alle Einträge gelesen werden müssen. Wenn Ihre Implementierung doppelte Schlüssel haben kann, dann lassen Sie den Return einfach weg. Dies spart die Kosten für das Lesen und das Forking von grep und awk. Die Verwendung von /dev/shm für beide Implementierungen ergab folgendes Ergebnis, wenn man time hget für einen Hash mit 3 Einträgen verwendet und nach dem letzten Eintrag sucht:

Grep/Awk:

hget() {
    grep "^$2 " /dev/shm/hashmap.$1 | awk '{ print $2 };'
}

$ time echo $(hget FD oracle)
3

real    0m0.011s
user    0m0.002s
sys     0m0.013s

Lesen/Echo:

$ time echo $(hget FD oracle)
3

real    0m0.004s
user    0m0.000s
sys     0m0.004s

Bei mehreren Aufrufen konnte ich nie eine Verbesserung von weniger als 50 % feststellen. Dies kann alles der Gabelung über Kopf zugeschrieben werden, die durch die Verwendung von /dev/shm .

2voto

kojiro Punkte 70709

Vor Bash 4 gibt es keine gute Möglichkeit, assoziative Arrays in Bash zu verwenden. Am besten ist es, eine interpretierte Sprache zu verwenden, die solche Dinge unterstützt, wie z.B. awk. Andererseits hat die bash 4 する sie unterstützen.

In Bezug auf weniger gute Möglichkeiten in bash 3, hier ist eine Referenz, die helfen könnte: http://mywiki.wooledge.org/BashFAQ/006

2voto

Milan Adamovsky Punkte 1451

Bash 3 Lösung:

Nachdem ich einige der Antworten gelesen habe, habe ich eine kleine Funktion zusammengestellt, mit der ich anderen helfen möchte.

# Define a hash like this
MYHASH=("firstName:Milan"
        "lastName:Adamovsky")

# Function to get value by key
getHashKey()
 {
  declare -a hash=("${!1}")
  local key
  local lookup=$2

  for key in "${hash[@]}" ; do
   KEY=${key%%:*}
   VALUE=${key#*:}
   if [[ $KEY == $lookup ]]
   then
    echo $VALUE
   fi
  done
 }

# Function to get a list of all keys
getHashKeys()
 {
  declare -a hash=("${!1}")
  local KEY
  local VALUE
  local key
  local lookup=$2

  for key in "${hash[@]}" ; do
   KEY=${key%%:*}
   VALUE=${key#*:}
   keys+="${KEY} "
  done

  echo $keys
 }

# Here we want to get the value of 'lastName'
echo $(getHashKey MYHASH[@] "lastName")

# Here we want to get all keys
echo $(getHashKeys MYHASH[@])

0 Stimmen

Ich denke, das ist ein ziemlich guter Ausschnitt. Es könnte ein wenig aufgeräumt werden (allerdings nicht viel). In meiner Version habe ich "key" in "pair" umbenannt und KEY und VALUE kleingeschrieben (weil ich Großbuchstaben verwende, wenn Variablen exportiert werden). Außerdem habe ich getHashKey in getHashValue umbenannt und sowohl key als auch value lokal gemacht (manchmal möchte man sie allerdings nicht lokal haben). In getHashKeys weise ich dem Wert nichts zu. Ich verwende Semikolon zur Trennung, da meine Werte URLs sind.

0voto

Alex Punkte 2660

Ich habe auch die bash4 Methode benutzt, aber ich habe einen ärgerlichen Fehler gefunden.

Ich brauchte, um dynamisch den assoziativen Array-Inhalt zu aktualisieren, so dass ich diesen Weg verwendet:

for instanceId in $instanceList
do
   aws cloudwatch describe-alarms --output json --alarm-name-prefix $instanceId| jq '.["MetricAlarms"][].StateValue'| xargs | grep -E 'ALARM|INSUFFICIENT_DATA'
   [ $? -eq 0 ] && statusCheck+=([$instanceId]="checkKO") || statusCheck+=([$instanceId]="allCheckOk"
done

Ich habe herausgefunden, dass mit Bash 4.3.11 das Anhängen an einen vorhandenen Schlüssel im Diktat dazu führte, dass der Wert angehängt wurde, wenn er bereits vorhanden war. So war zum Beispiel nach einigen Wiederholungen der Inhalt des Wertes "checkKOcheckKOallCheckOK" und das war nicht gut.

Kein Problem mit bash 4.3.39, wo das Anhängen eines existierenden Schlüssels bedeutet, dass der aktuelle Wert unterdrückt wird, wenn er bereits vorhanden ist.

Ich habe das Problem gelöst, indem ich das assoziative Array statusCheck vor der Zelle bereinigt/deklariert habe:

unset statusCheck; declare -A statusCheck

-2voto

Ich erstelle HashMaps in Bash 3 mit dynamischen Variablen. Ich habe erklärt, wie das funktioniert in meiner Antwort auf: Assoziative Arrays in Shell-Skripten

Sie können auch einen Blick werfen in shell_map die eine HashMap-Implementierung aus der Bash 3 ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X