Wie definieren hash-Tabellen in der Bash?
Was ist das äquivalent von Python-dictionaries aber in der Bash (sollte die Arbeit über OS X und Linux).
Haben bash ausführen eines python - /perl-Skript... Das ist so viel flexibler!
Erwägen Sie die Verwendung xonsh (es ist auf github).
Erwägen Sie die Verwendung xonsh (es ist auf github).
InformationsquelleAutor Sridhar Ratnakumar | 2009-09-29
Du musst angemeldet sein, um einen Kommentar abzugeben.
Bash 4
Bash 4 nativ unterstützt diese Funktion. Stellen Sie sicher, dass Ihr Skript die hashbang ist
#!/usr/bin/env bash
oder#!/bin/bash
so dass Sie nicht am Ende mitsh
. Stellen Sie sicher, dass Sie entweder bei der Ausführung Ihrer Skripts direkt aus, oder führen Siescript
mitbash script
. (Nicht tatsächlich ausführen eines Bash-Skript mit der Bash hat passieren, und wird wirklich verwirrend!)Sie deklarieren ein assoziatives array zu tun:
Können Sie füllen Sie ihn mit Elementen, die mit der normalen array-Zuweisung-operator. Zum Beispiel, wenn Sie wollen, um eine Karte von
animal[sound(key)] = animal(value)
:Oder verschmelzen Sie:
Dann verwenden Sie Sie einfach wie normale arrays. Verwenden
animals['key']='value'
den Wert festlegen,"${animals[@]}"
zu erweitern, die Werte und die"${!animals[@]}"
(beachten Sie die!
) erweitern Sie den Schlüssel. Vergessen Sie nicht, zu zitieren:Bash 3
Bevor bash 4, Sie haben keine assoziativen arrays. Nicht verwenden
eval
Sie zu emulieren. Vermeideneval
wie die Pest, weil es ist der Pest, die im shell-scripting. Der wichtigste Grund ist, dasseval
behandelt Ihre Daten als ausführbarer code (es gibt viele andere Gründe auch).In Erster Linie: Upgrade auf bash-4. Das macht den ganzen Prozess sehr viel einfacher für Sie.
Wenn es gibt einen Grund, Sie können nicht aktualisieren,
declare
ist eine viel sicherere option. Es bewertet nicht die Daten als bash-code wieeval
tut, und als solche nicht erlauben, willkürlichen code-Injektion ganz so leicht.Let ' s bereiten Sie die Antwort durch die Einführung der Konzepte:
Erste, Dereferenzierung.
Zweitens
declare
:Bringen Sie zusammen:
Lasst uns es verwenden:
Hinweis:
declare
genommen werden können, die in einer Funktion. Jede Verwendung vondeclare
innerhalb eines bash-Funktion wird die variable erstellt lokalen den Umfang, die Funktion, was bedeutet, wir können Sie nicht Zugriff oder ändern von globalen arrays. (In der bash 4 Sie können erklären,- g für das deklarieren von globalen Variablen, aber in der bash 4, können Sie assoziative arrays in den ersten Platz, vermeiden Sie diese Problemumgehung.)Zusammenfassung:
declare -A
für assoziative arrays.declare
option, wenn Sie nicht aktualisieren.awk
statt und vermeiden das Thema ganz.Kann nicht aktualisieren: der einzige Grund, warum ich Schreibe Skripte, die in Bash ist für "run anywhere" Portabilität. So unter Berufung auf eine nicht Universelle Funktion der Bash-Regeln dieses Vorgehen. Das ist schade, denn sonst wäre es eine ausgezeichnete Lösung für mich!
Es ist eine Schande, dass OSX standardmäßig auf Bash-3 noch als diese entspricht der "Standard" für eine Menge Leute. Ich dachte, die ShellShock erschrecken gewesen sein könnte, den push brauchte Sie aber offenbar nicht.
es ist ein Lizenzierungs-Problem. Bash auf OSX steckt in der neuesten nicht-GPLv3-lizenzierte bauen.
...oder
sudo port install bash
, für diejenigen, die (mit bedacht, IMHO) nicht bereit zu machen-Verzeichnisse in den PFAD für alle Nutzer schreibbar ist ohne ausdrückliche pro-Prozess-Privilegien-Eskalation.InformationsquelleAutor lhunath
Gibt es parameter-substitution, obwohl es vielleicht un-PC als auch ...wie Dereferenzierung.
Die BASH-4-way ist natürlich besser, aber wenn Sie benötigen ein hack ...nur ein hacken zu tun.
Suchen Sie das array/hash mit ähnlichen Techniken.
VALUE=${animal#*:}
zu schützen, für den Fall, woARRAY[$x]="caesar:come:see:conquer"
Es ist auch nützlich, um doppelte Anführungszeichen um das ${ARRAY[@]} in Fall gibt es Räume, in die Schlüssel oder Werte, wie in
for animal in "${ARRAY[@]}"; do
Aber ist nicht der Wirkungsgrad sehr schlecht ist? Ich bin am überlegen O(n*m) wenn Sie vergleichen wollen, um eine andere Liste von Tasten, die anstelle von O(n) mit der richtigen hashmaps (Konstante Zeit-lookup O(1) für einen einzelnen Schlüssel).
Die Idee ist, weniger Effizienz, mehr über verstehen/Lesen-Fähigkeit für diejenigen mit einem hintergrund in perl -, python-oder gar bash-4. Ermöglicht Ihnen das schreiben auf ähnliche Weise.
dies ist ein hack eine clevere und elegante, aber immer noch rudimentär workaround, um zu helfen die Armen Seelen noch immer in 2007 mit der Bash 3.x. Sie können nicht erwarten, dass "richtige hashmaps" oder die überlegungen zur Effizienz in einem so einfachen code.
InformationsquelleAutor Bubnoff
Dies ist, was ich suchte, hier:
Diese nicht für mich arbeiten mit der bash 4.1.5:
Upvote für die hashmap["key"]="Wert" die syntax, welche ich auch gefunden, fehlt in der ansonsten fantastischen akzeptierte Antwort.
Schlüssel weder fügt es mehrere Schlüssel. Irgendeiner Weise zu umgehen?
InformationsquelleAutor aktivb
Können Sie weitere änderungen an der hput()/hget () - Schnittstelle, so dass Sie benannt haben-hashes wie folgt:
dann
So können Sie definieren, von anderen Karten, die nicht im Konflikt (z.B., 'rcapitals', die nicht Land-Suche nach capital city). Aber, so oder so, ich denke, Sie werden feststellen, dass dies alles ziemlich schrecklich, performance-wise.
Wenn Sie wirklich wollen, schnellen hash-lookup, es ist eine schreckliche, schreckliche hack, der wirklich funktioniert wirklich gut. Ist es diese: schreiben Sie Ihre Schlüssel/Werte in eine temporäre Datei, eine pro Zeile, dann benutze 'grep "^$ - Taste"', um Sie aus, die durch Rohre mit cut oder awk oder sed oder was auch immer, um die Werte abzurufen.
Wie gesagt, es klingt schrecklich, und es klingt wie es sollte langsam sein und alles mögliche tun, um unnötige IO, aber in der Praxis ist es sehr schnell (disk-cache ist genial, ist es nicht?), auch für sehr große hash-Tabellen. Sie haben zur Durchsetzung der Schlüssel Einzigartigkeit sich selbst, usw. Auch wenn Sie nur ein paar hundert Einträge, die Ausgabe-Datei/grep-combo geht um einiges schneller - meiner Erfahrung nach um ein Vielfaches schneller. Es frisst auch weniger Speicher.
Hier ist ein Weg, es zu tun:
InformationsquelleAutor Al P.
Benutzen Sie einfach die Datei system
Die Datei system ist eine Baum-Struktur, die verwendet werden können, wie eine hash-map.
Ihre hash-Tabelle wird ein temporäres Verzeichnis, wird Ihr privater Schlüssel Dateinamen, und Ihre Werte werden in der Datei-Inhalt. Der Vorteil ist, dass Sie mit riesigen hashmaps, und nicht um eine spezifische Schale.
Hashtable anlegen
hashtable=$(mktemp -d)
Fügen Sie ein element
echo $value > $hashtable/$key
Lesen eines Elements
value=$(< $hashtable/$key)
Leistung
Natürlich, seine langsam, aber nicht , dass langsam.
Getestet habe ich es auf meinem Rechner mit einer SSD und btrfs, und um 3000-element Lesen/schreiben pro Sekunde.
mkdir -d
? (Nicht 4.3, auf Ubuntu 14. Ich würde resort zumkdir /run/shm/foo
oder wenn, gefüllt RAM,mkdir /tmp/foo
.)Vielleicht
mktemp -d
gemeint war stattdessen?Neugierig, was ist der Unterschied zwischen
$value=$(< $hashtable/$key)
undvalue=$(< $hashtable/$key)
? Danke!"es getestet auf meinem Computer", Das klingt wie ein guter Weg, um zu brennen ein Loch durch die SSD. Nicht alle Linux-Distributionen verwenden tmpfs standardmäßig.
Ich bin von der Verarbeitung über 50000 hashes. Perl und PHP machen es ein Haar unter 1/2 Sekunde. Knoten in 1 Sekunde und so etwas. FS-option klingt langsam. Jedoch können wir sicherstellen, dass die Dateien existieren nur im RAM, irgendwie?
InformationsquelleAutor lovasoa
können Sie erklären, was ist die Verwendung von #in hash eval echo '${hash'"$1"'#hash}'. für mich scheint es mir als Kommentar nicht mehr als das. tut #hash haben, eine Besondere Bedeutung hier?
eval-Befehl nicht gefunden
entfernt den text start vom Anfang des gespeicherten Wert in der Variablen var.
InformationsquelleAutor DigitalRoss
Betrachten Sie eine Lösung mittels der bash-builtin Lesen, wie dargestellt in der code-snippet, das von einer ufw firewall-Skript, das folgt. Dieser Ansatz hat den Vorteil, mit wie vielen abgegrenzte Feld setzt (nicht nur 2), wie gewünscht. Wir haben die | Trennzeichen, weil der port-Bereich-Bezeichner erfordern einen Doppelpunkt, dh 6001:6010.
IFS=$'|' read -r first rest <<< "$fields"
InformationsquelleAutor AsymLabs
Stimme ich mit @lhunath und andere, die das assoziative array sind der Weg zu gehen mit Bash-4. Wenn Sie stecken bleiben auf Bash-3 (OSX, alte Distributionen, die Sie nicht aktualisieren kann), können Sie sich auch expr, die sollte überall sein, eine string-und regular expressions. Ich mag es vor allem, wenn das Wörterbuch nicht zu groß ist.
Schreiben Sie Ihre map als string (beachten Sie das Trennzeichen ',' auch am Anfang und am Ende)
Einen regex verwenden, zum extrahieren der Werte
Split der string-Liste, die Elemente, die
Nun können Sie es verwenden:
InformationsquelleAutor marco
Ich mochte Al P s beantworten, aber wollte Einzigartigkeit durchgesetzt Billig also habe ich es einen Schritt weiter - Verzeichnis. Es gibt einige offensichtliche Einschränkungen (Verzeichnis, Datei Grenzen, ungültige Dateinamen), es sollte aber für die meisten Fälle.
Verhält es sich auch einen Tick besser in meinen tests.
Dachte nur, ich pitch in. Prost!
Bearbeiten: Hinzufügen hdestroy()
InformationsquelleAutor Cole Stanfield
Vor bash 4 es ist kein guter Weg, um die Verwendung von assoziativen arrays in der bash. Ihre beste Wette ist, um zu verwenden, eine interpretierte Sprache, die tatsächlich Unterstützung für solche Dinge, wie awk. Auf der anderen Seite, bash 4 hat unterstützen.
Als für weniger gute Möglichkeiten in der bash 3, hier ist ein Verweis als helfen könnte: http://mywiki.wooledge.org/BashFAQ/006
InformationsquelleAutor kojiro
Zwei Dinge, die Sie verwenden können Speicher anstelle von /tmp in jedem kernel 2.6 durch die Verwendung von /dev/shm (Redhat) anderen Distributionen variieren. Auch hget werden kann reimplementiert mit Lesen Sie wie folgt vor:
Zusätzlich von der Annahme, dass alle keys sind einzigartig, die Rückkehr Kurzschlüsse die lese-Schleife, und verhindert, dass Lesen durch alle Einträge. Wenn Ihre Implementierung haben, können doppelte Schlüssel, dann einfach lassen sich die Rückkehr. Dadurch entfällt der Aufwand für das Lesen und die Verzweigung sowohl grep und awk. Die Verwendung von /dev/shm für beide Implementierungen ergab die folgenden using-Zeit, hget bei einer 3 hash-Eintrag der Suche nach dem letzten Eintrag :
Grep/Awk:
Lesen/echo:
auf mehrere Aufrufe habe ich nie weniger als eine 50% ige Verbesserung.
Dies alles kann zurückgeführt werden auf den Tisch über den Kopf, durch den Einsatz von
/dev/shm
.InformationsquelleAutor jrichard
Bash 3 Lösung:
In der Lektüre einige der Antworten, die ich zusammen gestellt habe schnell eine kleine Funktion möchte ich etwas zurück geben, das könnte anderen helfen.
InformationsquelleAutor Milan Adamovsky
Ein Kollege gerade erwähnt in diesem thread. Ich habe unabhängig voneinander umgesetzt hash-Tabellen innerhalb der bash, und es ist nicht abhängig von der version 4. Aus einem blog post von mir im März 2010 (vor den Antworten hier...) berechtigt Hash-Tabellen in der bash:
Ich zuvor verwendet
cksum
hash-aber da übersetzt Java string hashCode native bash/zsh.Es ist nicht bidirektional, und die integrierte Möglichkeit ist viel besser, aber Sie sollten nicht wirklich verwendet werden, sowieso. Bash ist für den schnellen one-offs, und solche Dinge sollten ganz selten betreffen die Komplexität, die möglicherweise hashes, außer vielleicht in Ihrer
~/.bashrc
und Freunde.Ja, meine website ist down und ich bezweifle, ich werde wieder auferstehen meinem blog. Ich habe aktualisiert den obigen link auf eine archivierte version. Vielen Dank für Ihr Interesse!
InformationsquelleAutor Adam Katz
Ich auch, dass die bash4 Weg, aber ich finden und lästige Fehler.
Brauchte ich, um die sich dynamisch aktualisieren, die assoziative array-Inhalt, so habe ich auf diese Weise:
Finde ich heraus, dass mit der bash 4.3.11 anfügen an einen bestehenden Schlüssel im dict geführt, indem der Wert, wenn bereits vorhanden. So zum Beispiel nach einem repetion der Inhalte der Wert war "checkKOcheckKOallCheckOK" und das war nicht gut.
Kein problem mit bash 4.3.39, wo appenging einen vorhandenen Schlüssel zu substisture die actuale Wert, wenn bereits vorhanden.
Löste ich dieses nur Reinigung/deklarieren der statusCheck assoziatives array, bevor Sie den Turnus:
InformationsquelleAutor Alex
Erstelle ich HashMaps in bash 3 mit dynamischen Variablen. Ich habe erklärt, wie das funktioniert, dass meine Antwort auf: Assoziative arrays in Shell-Skripten
Außerdem können Sie einen Blick in shell_map, die eine HashMap-Implementierung made in bash 3.
InformationsquelleAutor Bruno Negrão Zica