Co jest odpowiednikiem słowników Python, ale w Bash (powinno działać w systemach OS X i Linux).
bash
dictionary
hashtable
associative-array
Sridhar Ratnakumar
źródło
źródło
Odpowiedzi:
Bash 4
Bash 4 natywnie obsługuje tę funkcję. Upewnij się hashbang skrypcie jest
#!/usr/bin/env bash
albo#!/bin/bash
więc nie kończy się przy użyciush
. Upewnij się, że albo wykonujesz skrypt bezpośrednio, albo wykonujeszscript
gobash script
. (Nie faktycznie wykonujący skrypt Bash z Basha nie stało, i będzie bardzo mylące!)Deklarujesz tablicę asocjacyjną, wykonując:
Możesz wypełnić go elementami za pomocą normalnego operatora przypisania tablicy. Na przykład, jeśli chcesz mieć mapę
animal[sound(key)] = animal(value)
:Lub scal je:
Następnie używaj ich tak jak normalnych tablic. Posługiwać się
animals['key']='value'
ustawić wartość"${animals[@]}"
aby rozwinąć wartości"${!animals[@]}"
(zauważ!
), aby rozwinąć kluczeNie zapomnij ich zacytować:
Bash 3
Przed bash 4 nie masz tablic asocjacyjnych. Nie używaj ich
eval
do emulacji . Unikajeval
jak zarazy, ponieważ jest to plaga skryptów powłoki. Najważniejszym powodem jest to, żeeval
traktuje twoje dane jako kod wykonywalny (istnieje również wiele innych powodów).Przede wszystkim : rozważ aktualizację do wersji bash 4. Ułatwi to cały proces.
Jeśli istnieje powód, dla którego nie można dokonać aktualizacji,
declare
jest to znacznie bezpieczniejsza opcja. Nie ocenia danych jako kodu bashowegoeval
robi i jako taki nie pozwala na tak łatwe wprowadzanie dowolnego kodu.Przygotujmy odpowiedź, wprowadzając pojęcia:
Po pierwsze, pośredniość.
Po drugie
declare
:Połącz je razem:
Użyjmy tego:
Uwaga:
declare
nie można wprowadzić funkcji. Każde użyciedeclare
funkcji bash zmienia lokalną zmienną, którą tworzy się w zakres tej funkcji, co oznacza, że nie możemy uzyskać do niej dostępu ani modyfikować tablic globalnych. (W bash 4 możesz użyć deklaruj -g, aby deklarować zmienne globalne - ale w bash 4 możesz w pierwszej kolejności używać tablic asocjacyjnych, unikając tego obejścia).Podsumowanie:
declare -A
dla tablic asocjacyjnych.declare
opcji, jeśli nie możesz zaktualizować.awk
zamiast tego i całkowicie unikaj problemu.źródło
4.x
a niey
.sudo port install bash
dla tych (mądrze, IMHO), którzy nie chcą, aby katalogi w PATH były zapisywane dla wszystkich użytkowników bez wyraźnej eskalacji uprawnień dla poszczególnych procesów.Istnieje podstawianie parametrów, chociaż może to być również nie na PC ... jak pośrednie.
Oczywiście sposób BASH 4 jest lepszy, ale jeśli potrzebujesz hacka ... wystarczy hack. Możesz przeszukiwać tablicę / skrót za pomocą podobnych technik.
źródło
VALUE=${animal#*:}
ARRAY[$x]="caesar:come:see:conquer"
for animal in "${ARRAY[@]}"; do
Oto, czego szukałem tutaj:
Nie działało to dla mnie w wersji bash 4.1.5:
źródło
Możesz dalej zmodyfikować interfejs hput () / hget (), tak aby nazwać skróty w następujący sposób:
i wtedy
Pozwala to zdefiniować inne mapy, które nie powodują konfliktów (np. „Rcapitals”, które wyszukują dane według stolic). Ale tak czy inaczej, myślę, że przekonasz się, że to wszystko jest okropne, pod względem wydajności.
Jeśli naprawdę chcesz szybkiego wyszukiwania skrótów, istnieje straszny, straszny hack, który naprawdę działa naprawdę dobrze. Jest to: zapisz klucz / wartości do pliku tymczasowego, jeden na linię, a następnie użyj „grep” ^ $ klucz ”, aby je wyciągnąć, używając rur z cięciem, awk, sed lub cokolwiek innego, aby odzyskać wartości.
Tak jak powiedziałem, brzmi to okropnie i wygląda na to, że powinien być powolny i robić wszelkiego rodzaju niepotrzebne operacje wejścia / wyjścia, ale w praktyce jest bardzo szybki (pamięć podręczna dysku jest niesamowita, prawda?), Nawet w przypadku bardzo dużego skrótu stoły Sam musisz wymusić unikalność klucza itp. Nawet jeśli masz tylko kilkaset wpisów, kombinacja pliku wyjściowego / grep będzie nieco szybsza - z mojego doświadczenia kilka razy szybsza. Zjada także mniej pamięci.
Oto jeden ze sposobów, aby to zrobić:
źródło
Po prostu użyj systemu plików
System plików to struktura drzewa, która może być używana jako mapa mieszania. Tabela skrótów będzie katalogiem tymczasowym, klucze będą nazwami plików, a wartości będą zawartością plików. Zaletą jest to, że może obsługiwać ogromne mapy skrótów i nie wymaga konkretnej powłoki.
Tworzenie haszyszu
hashtable=$(mktemp -d)
Dodaj element
echo $value > $hashtable/$key
Przeczytaj element
value=$(< $hashtable/$key)
Wydajność
Oczywiście jest wolny, ale nie taki wolny. Przetestowałem to na moim komputerze, z dyskiem SSD i btrfs , i robi około 3000 elementów odczytu / zapisu na sekundę .
źródło
mkdir -d
? (Nie 4.3, na Ubuntu 14. Chciałbym skorzystać zmkdir /run/shm/foo
, lub jeśli to zapełniłoby RAMmkdir /tmp/foo
mktemp -d
zamiast tego miał na myśli?$value=$(< $hashtable/$key)
ivalue=$(< $hashtable/$key)
? Dzięki!źródło
${var#start}
usuwa tekst zaczynający się od początku wartości przechowywanej w zmiennej var .Rozważ rozwiązanie wykorzystujące wbudowany bash odczytany jak pokazano we fragmencie kodu z następującego skryptu zapory ufw. Zaletą tego podejścia jest wykorzystanie dowolnej liczby zestawów pól rozdzielanych (nie tylko 2). Użyliśmy | ogranicznik, ponieważ specyfikatory zakresu portów mogą wymagać dwukropka, tj. 6001: 6010 .
źródło
IFS=$'|' read -r first rest <<< "$fields"
Zgadzam się z @lhunath i innymi, że tablica asocjacyjna jest najlepszym rozwiązaniem dla Bash 4. Jeśli utkniesz w Bash 3 (OSX, stare dystrybucje, których nie możesz zaktualizować), możesz również użyć wyrażenia, które powinno być wszędzie, ciąg i wyrażenia regularne. Podoba mi się to szczególnie, gdy słownik nie jest zbyt duży.
Napisz swoją mapę jako ciąg znaków (zwróć uwagę na separator „,” również na początku i na końcu)
Użyj wyrażenia regularnego, aby wyodrębnić wartości
Podziel ciąg, aby wyświetlić listę elementów
Teraz możesz go użyć:
źródło
Naprawdę podobała mi się odpowiedź Al P, ale chciałem tanio egzekwować tanio, więc posunąłem się o krok dalej - skorzystaj z katalogu. Istnieją pewne oczywiste ograniczenia (limity plików katalogu, nieprawidłowe nazwy plików), ale powinno to działać w większości przypadków.
W moich testach działa też odrobinę lepiej.
Pomyślałem, że się wtrącę.
Edycja: dodawanie hdestroy ()
źródło
Dwie rzeczy, możesz użyć pamięci zamiast / tmp w dowolnym jądrze 2.6, używając / dev / shm (Redhat), inne dystrybucje mogą się różnić. Również hget można ponownie zaimplementować, używając następującego odczytu:
Ponadto, zakładając, że wszystkie klucze są unikalne, powrót powoduje zwarcie pętli odczytu i zapobiega konieczności odczytu wszystkich wpisów. Jeśli twoja implementacja może mieć zduplikowane klucze, po prostu pomiń zwrot. Oszczędza to kosztów czytania i tworzenia zarówno grep, jak i awk. Użycie / dev / shm dla obu implementacji dało następujące użycie hgetu czasowego w haszu z 3 pozycjami w poszukiwaniu ostatniego wpisu:
Grep / Awk:
Odczyt / echo:
przy wielu inwokacjach nigdy nie widziałem mniej niż 50% poprawy. Można to wszystko przypisać widelcowi ponad głową, ze względu na użycie
/dev/shm
.źródło
Współpracownik właśnie wspomniał o tym wątku. Niezależnie zaimplementowałem tabele skrótów w bash i nie jest to zależne od wersji 4. Z mojego posta na blogu w marcu 2010 roku (przed niektórymi odpowiedziami tutaj ...) zatytułowanym Tabele skrótów w bash :
Ja poprzednio używany
cksum
do hash ale ponieważ tłumaczone ciąg hashCode Javy do rodzimej bash / zsh.Nie jest dwukierunkowy, a wbudowany sposób jest o wiele lepszy, ale i tak nie należy go używać. Bash jest przeznaczony do szybkich działań jednorazowych i takie rzeczy rzadko powinny wiązać się ze złożonością, która może wymagać skrótów, chyba że u ciebie
~/.bashrc
i twoich przyjaciół.źródło
Przed bash 4 nie ma dobrego sposobu na użycie tablic asocjacyjnych w bash. Najlepiej jest użyć przetłumaczonego języka, który faktycznie obsługuje takie rzeczy, jak awk. Z drugiej strony bash 4 tak wspierać je.
Jeśli chodzi o mniej dobre sposoby w bash 3, oto odniesienie, które może pomóc: http://mywiki.wooledge.org/BashFAQ/006
źródło
Rozwiązanie Bash 3:
Czytając niektóre odpowiedzi, przygotowałem krótką funkcję, którą chciałbym wesprzeć, która mogłaby pomóc innym.
źródło
Użyłem również sposobu bash4, ale znajduję irytujący błąd.
Musiałem dynamicznie aktualizować zawartość tablicy asocjacyjnej, więc skorzystałem z tego sposobu:
Przekonałem się, że dodanie bash 4.3.11 do istniejącego klucza w dykcie spowodowało dodanie wartości, jeśli już jest obecna. Na przykład po pewnym powtórzeniu treść wartości brzmiała „checkKOcheckKOallCheckOK”, co nie było dobre.
Nie ma problemu z wersją bash 4.3.39, gdzie dołączenie istniejącego klucza oznacza zastąpienie wartości aktualnej, jeśli jest już obecna.
Rozwiązałem to tylko czyszczenie / deklarowanie tablicy asocjacyjnej statusCheck przed cyklem:
źródło
HashMapy tworzę w bash 3 przy użyciu zmiennych dynamicznych. Wyjaśniłem, jak to działa w mojej odpowiedzi na: Tablice asocjacyjne w skryptach Shell
Możesz także rzucić okiem na shell_map , czyli implementację HashMap wykonaną w bash 3.
źródło