Что эквивалентно словарям Python, но в Bash (должно работать в OS X и Linux).
bash
dictionary
hashtable
associative-array
Шридхар Ратнакумар
источник
источник
Ответы:
Баш 4
Bash 4 изначально поддерживает эту функцию. Убедитесь, что ваш скрипт имеет хэшбэнг,
#!/usr/bin/env bash
или#!/bin/bash
вы его не используетеsh
. Убедитесь, что вы выполняете сценарий напрямую или выполняетеscript
с помощьюbash script
. (Не на самом деле выполнение сценарий Bash с Bash действительно произойдет, и будет очень запутанные!)Вы объявляете ассоциативный массив, выполняя:
Вы можете заполнить его элементами, используя обычный оператор присваивания массива. Например, если вы хотите иметь карту
animal[sound(key)] = animal(value)
:Или объединить их:
Затем используйте их как обычные массивы. использование
animals['key']='value'
установить значение"${animals[@]}"
расширить значения"${!animals[@]}"
(обратите внимание!
), чтобы расширить ключиНе забудьте процитировать их:
Баш 3
До bash 4 у вас не было ассоциативных массивов. Не используйте,
eval
чтобы подражать им . Избегайте ,eval
как чумы, потому что это чума сценариев оболочки. Наиболее важной причиной является то, чтоeval
ваши данные обрабатываются как исполняемый код (есть и много других причин).Прежде всего : рассмотрите возможность обновления до bash 4. Это значительно облегчит вам весь процесс.
Если есть причина, по которой вы не можете выполнить обновление,
declare
это гораздо более безопасный вариант. Он не оценивает данные так, как этоeval
делает bash-код , и поэтому не позволяет легко вводить произвольный код.Давайте подготовим ответ, введя понятия:
Во-первых, косвенность.
Во- вторых,
declare
:Соберите их вместе:
Давайте использовать это:
Примечание:
declare
нельзя вставить в функцию. Любое использованиеdeclare
внутри функции Баша превращает переменную она создает локальную в рамки этой функции, то есть мы не можем получить доступ или изменить глобальные массивы с ним. (В bash 4 вы можете использовать объявление -g для объявления глобальных переменных - но в bash 4 вы можете использовать ассоциативные массивы в первую очередь, избегая этого обходного пути.)Резюме:
declare -A
для ассоциативных массивов.declare
опцию, если вы не можете обновить.awk
вместо этого и избежать проблемы в целом.источник
4.x
а не такy
.sudo port install bash
для тех (мудро, IMHO), которые не хотят делать каталоги в PATH для всех пользователей, доступных для записи без явного повышения привилегий для каждого процесса.Есть подстановка параметров, хотя это может быть и без ПК ... как косвенное обращение.
BASH 4, конечно, лучше, но если вам нужен взлом ... подойдет только взлом. Вы можете искать массив / хэш с подобными методами.
источник
VALUE=${animal#*:}
защитить случай, когдаARRAY[$x]="caesar:come:see:conquer"
for animal in "${ARRAY[@]}"; do
Вот что я искал здесь:
Это не работает для меня с Bash 4.1.5:
источник
Вы можете дополнительно изменить интерфейс hput () / hget (), чтобы хэши назывались следующим образом:
а потом
Это позволяет вам определять другие карты, которые не конфликтуют (например, «rcapitals», которая выполняет поиск страны по столице). Но, так или иначе, я думаю, вы обнаружите, что все это довольно ужасно с точки зрения производительности.
Если вы действительно хотите быстрый поиск хеша, есть ужасный, ужасный хак, который действительно работает очень хорошо. Это так: запишите ваш ключ / значения во временный файл, по одному на строку, а затем используйте 'grep "^ $ key"', чтобы получить их, используя каналы с cut или awk или sed или что-то еще для получения значений.
Как я уже сказал, это звучит ужасно, и звучит так, как будто оно должно быть медленным и выполнять все виды ненужных операций ввода-вывода, но на практике это очень быстро (кеш диска - это круто, не правда ли?), Даже для очень большого хэша столы. Вы должны сами установить уникальность ключа и т. Д. Даже если у вас всего несколько сотен записей, комбинация выходного файла / grep будет немного быстрее - по моему опыту, в несколько раз быстрее. Это также ест меньше памяти.
Вот один из способов сделать это:
источник
Просто используйте файловую систему
Файловая система представляет собой древовидную структуру, которую можно использовать в качестве хэш-карты. Ваша хеш-таблица будет временным каталогом, ваши ключи будут именами файлов, а ваши значения будут содержимым файла. Преимущество заключается в том, что он может обрабатывать огромные хеш-карты и не требует специальной оболочки.
Создание хэш-таблицы
hashtable=$(mktemp -d)
Добавить элемент
echo $value > $hashtable/$key
Читать элемент
value=$(< $hashtable/$key)
Представление
Конечно, его медленно, но не , что медленно. Я протестировал его на своей машине, с SSD и btrfs , и он делает около 3000 элементов чтения / записи в секунду .
источник
mkdir -d
? (Не 4.3, на Ubuntu 14. Я бы прибегнулmkdir /run/shm/foo
или, если бы это заполнило ОЗУmkdir /tmp/foo
.)mktemp -d
имелось ввиду вместо этого?$value=$(< $hashtable/$key)
иvalue=$(< $hashtable/$key)
? Спасибо!источник
${var#start}
удаляет текст старт с начала значения , хранящегося в переменной Var .Рассмотрим решение с использованием встроенного чтения bash, как показано во фрагменте кода из сценария брандмауэра ufw, который следует ниже. Этот подход имеет то преимущество, что использует столько разделенных наборов полей (а не только 2), сколько необходимо. Мы использовали | разделитель, потому что спецификаторам диапазона портов может потребоваться двоеточие, то есть 6001: 6010 .
источник
IFS=$'|' read -r first rest <<< "$fields"
Я согласен с @lhunath и другими, что ассоциативный массив - это путь к Bash 4. Если вы застряли в Bash 3 (OSX, старые дистрибутивы, которые вы не можете обновить), вы можете использовать также expr, который должен быть везде, строку и регулярные выражения. Мне особенно нравится, когда словарь не слишком большой.
Напишите вашу карту в виде строки (обратите внимание на разделитель ',' также в начале и в конце)
Используйте регулярное выражение для извлечения значений
Разделить строку, чтобы перечислить элементы
Теперь вы можете использовать его:
источник
Мне очень понравился ответ Аль П, но я хотел, чтобы уникальность была обеспечена дешево, поэтому я сделал еще один шаг вперед - использовал каталог. Существуют некоторые очевидные ограничения (ограничения файлов каталога, недопустимые имена файлов), но это должно работать в большинстве случаев.
Он также работает немного лучше в моих тестах.
Просто подумал, что я смогу участвовать. Ура!
Редактировать: Добавление hdestroy ()
источник
Две вещи: вы можете использовать память вместо / tmp в любом ядре 2.6, используя / dev / shm (Redhat), другие дистрибутивы могут отличаться. Также hget может быть переопределён следующим образом:
Кроме того, предполагая, что все ключи уникальны, возврат замыкает цикл чтения и предотвращает необходимость чтения всех записей. Если ваша реализация может иметь дубликаты ключей, просто опустите возврат. Это экономит расходы на чтение и разветвление как grep, так и awk. Использование / dev / shm для обеих реализаций дало следующее использование time hget для хеша с 3 записями, ищущего последнюю запись:
Grep / Awk:
Чтение / эхо:
при многократных вызовах я никогда не видел улучшения менее чем на 50%. Это все можно отнести к форк над головой, из-за использования
/dev/shm
.источник
Коллега только что упомянул эту тему. Я независимо реализовал хеш-таблицы в bash, и это не зависит от версии 4. Из моего поста в блоге в марте 2010 года (до некоторых ответов здесь ...), озаглавленного Хеш-таблицы в bash :
Ранее я использовал
cksum
для хэширования, но с тех пор перевел строковый хэш-код Java в нативный bash / zsh.Он не двунаправленный, а встроенный способ намного лучше, но в любом случае его не следует использовать. Bash предназначен для быстрой разовой игры, и такие вещи довольно редко должны включать сложность, которая может потребовать хэшей, за исключением, возможно, ваших
~/.bashrc
и ваших друзей.источник
До bash 4 не было хорошего способа использовать ассоциативные массивы в bash. Лучше всего использовать интерпретированный язык, который действительно поддерживает такие вещи, как awk. С другой стороны, Баш 4 делает их поддержки.
Что касается менее хороших способов в bash 3, вот ссылка, которая может помочь: http://mywiki.wooledge.org/BashFAQ/006
источник
Решение Bash 3:
Читая некоторые ответы, я собрал небольшую небольшую функцию, которую я хотел бы внести в ответ, которая может помочь другим.
источник
Я также использовал способ bash4, но я нахожу и раздражает ошибку.
Мне нужно было динамически обновлять содержимое ассоциативного массива, поэтому я использовал этот способ:
Я обнаружил, что с bash 4.3.11 добавление существующего ключа в dict привело к добавлению значения, если оно уже присутствует. Так, например, после некоторого повторения содержание значения было «checkKOcheckKOallCheckOK», и это не было хорошо.
Нет проблем с bash 4.3.39, где добавление существующего ключа означает замещение действительного значения, если оно уже присутствует.
Я решил это просто очистив / объявив ассоциативный массив statusCheck перед циклом:
источник
Я создаю HashMaps в Bash 3, используя динамические переменные. Я объяснил, как это работает в моем ответе на: Ассоциативные массивы в скриптах Shell
Также вы можете взглянуть на shell_map , который является реализацией HashMap, сделанной в bash 3.
источник