Нам нужен сценарий, который имитирует ассоциативные массивы или структуру данных типа Map для сценариев оболочки, любое тело?
bash
shell
hashtable
associative-array
Ирфан Зульфикар
источник
источник
Другой вариант, если переносимость не является вашей основной задачей, - использовать ассоциативные массивы, встроенные в оболочку. Это должно работать в bash 4.0 (доступно сейчас в большинстве основных дистрибутивов, но не в OS X, если вы не установите его самостоятельно), ksh и zsh:
В зависимости от оболочки вам может потребоваться выполнить a
typeset -A newmap
вместоdeclare -A newmap
или в некоторых случаях это может не понадобиться вовсе.источник
test -z ${variable+x}
(x
не имеет значения, это может быть любая строка). Для ассоциативного массива в Bash вы можете сделать то же самое; использоватьtest -z ${map[key]+x}
.Другой способ, не связанный с bash 4.
Вы также можете добавить оператор if для поиска. если [[$ var = ~ / blah /]]. или что угодно.
источник
Я думаю, что вам нужно сделать шаг назад и подумать о том, что на самом деле представляет собой карта или ассоциативный массив. Все это способ сохранить значение для данного ключа и быстро и эффективно вернуть это значение. Вы также можете захотеть перебрать ключи для получения каждой пары ключ-значение или удалить ключи и связанные с ними значения.
Теперь подумайте о структуре данных, которую вы все время используете в сценариях оболочки и даже просто в оболочке без написания сценария, обладающего этими свойствами. Тупик? Это файловая система.
На самом деле, все, что вам нужно, чтобы иметь ассоциативный массив при программировании оболочки, - это временный каталог.
mktemp -d
ваш конструктор ассоциативного массива:Если вам не хочется использовать
echo
иcat
, вы всегда можете написать несколько маленьких оберток; эти модели созданы по образцу Irfan, хотя они просто выводят значение, а не устанавливают произвольные переменные, например$value
:edit : этот подход на самом деле немного быстрее, чем линейный поиск с использованием sed, предложенный задающим вопрос, а также более надежен (он позволяет ключам и значениям содержать -, =, пробел, qnd ": SP:"). Тот факт, что он использует файловую систему, не замедляет его; эти файлы никогда не гарантированно будут записаны на диск, если вы не позвоните
sync
; для подобных временных файлов с коротким сроком жизни не исключено, что многие из них никогда не будут записаны на диск.Я провел несколько тестов кода Ирфана, модификации кода Ирфана Джерри и своего кода, используя следующую программу-драйвер:
Результаты:
источник
Bash4 изначально поддерживает это. Не используйте
grep
илиeval
, это самый уродливый из хаков.Подробный, подробный ответ с примером кода см .: /programming/3467959
источник
Пример:
источник
Теперь отвечу на этот вопрос.
Следующие сценарии моделируют ассоциативные массивы в сценариях оболочки. Это просто и очень легко понять.
Карта - это не что иное, как бесконечная строка, в которой keyValuePair сохранен как --name = Irfan --designation = SSE --company = My: SP: Own: SP: Company
пробелы заменяются на ': SP:' для значений
изменить: просто добавил еще один метод для получения всех ключей.
источник
eval
вводите данные, как если бы это был код на bash, и более того: вы неправильно их цитируете. Оба вызывают массу ошибок и произвольное внедрение кода.Для Bash 3 есть частный случай, у которого есть хорошее и простое решение:
Если вы не хотите обрабатывать большое количество переменных или ключи являются просто недопустимыми идентификаторами переменных, и ваш массив гарантированно содержит менее 256 элементов , вы можете злоупотреблять возвращаемыми значениями функции. Это решение не требует какой-либо подоболочки, поскольку значение легко доступно в виде переменной, а также каких-либо итераций, чтобы производительность кричала. Также он очень удобочитаемый, почти как версия Bash 4.
Вот самая простая версия:
Помните, используйте одинарные кавычки
case
, иначе это может быть подстановкой. Действительно полезно для статических / замороженных хэшей с самого начала, но можно написать генератор индекса изhash_keys=()
массива.Остерегайтесь, по умолчанию используется первый, поэтому вы можете отложить нулевой элемент:
Предупреждение: длина теперь неверная.
В качестве альтернативы, если вы хотите сохранить индексирование с нуля, вы можете зарезервировать другое значение индекса и защититься от несуществующего ключа, но он менее читабелен:
Или, чтобы сохранить правильную длину, сместите индекс на единицу:
источник
Вы можете использовать имена динамических переменных и позволить именам переменных работать как ключи хэш-карты.
Например, если у вас есть входной файл с двумя столбцами, имя, кредит, как в примере ниже, и вы хотите просуммировать доход каждого пользователя:
Приведенная ниже команда просуммирует все, используя динамические переменные в качестве ключей в форме map _ $ {person} :
Чтобы прочитать результаты:
Результат будет:
Разрабатывая эти методы, я разрабатываю на GitHub функцию, которая работает так же, как объект HashMap , shell_map .
Для создания « экземпляров HashMap » функция shell_map может создавать свои копии под разными именами. Каждая новая копия функции будет иметь другую переменную $ FUNCNAME. Затем $ FUNCNAME используется для создания пространства имен для каждого экземпляра карты.
Ключи карты - это глобальные переменные в форме $ FUNCNAME_DATA_ $ KEY, где $ KEY - это ключ, добавленный в карту. Эти переменные являются динамическими переменными .
Ниже я помещу его упрощенную версию, чтобы вы могли использовать ее в качестве примера.
Использование:
источник
Еще один способ, отличный от bash-4 (т. Е. Bash 3, совместимый с Mac):
Печать:
Функция с
case
элементами действует как ассоциативный массив. К сожалению, он не может использоватьreturn
, поэтому он долженecho
выводить его, но это не проблема, если вы не пурист, который избегает разветвления подоболочки.источник
Как жаль, что я не видел этого вопроса раньше - я написал библиотеку- оболочку, которая содержит среди прочего карты (ассоциативные массивы). Последнюю версию можно найти здесь .
Пример:
источник
Добавляем еще один вариант, если доступен jq:
источник
Как уже упоминалось, я обнаружил, что наиболее эффективный метод - это записать key / vals в файл, а затем использовать grep / awk для их получения. Это звучит как всевозможные ненужные операции ввода-вывода, но дисковый кеш срабатывает и делает его чрезвычайно эффективным - намного быстрее, чем пытаться сохранить их в памяти с помощью одного из вышеперечисленных методов (как показывают тесты).
Вот быстрый и чистый метод, который мне нравится:
Если вы хотите применить одно значение для каждого ключа, вы также можете выполнить небольшое действие grep / sed в hput ().
источник
Несколько лет назад я написал библиотеку сценариев для bash, которая среди других функций поддерживала ассоциативные массивы (ведение журнала, файлы конфигурации, расширенная поддержка аргументов командной строки, создание справки, модульное тестирование и т. д.). Библиотека содержит оболочку для ассоциативных массивов и автоматически переключается на соответствующую модель (внутреннюю для bash4 и эмулируемую для предыдущих версий). Он назывался shell-framework и размещался на сайте origo.ethz.ch, но сегодня ресурс закрыт. Если кому-то это все еще нужно, могу поделиться с вами.
источник
В оболочке нет встроенной карты, такой как структура данных, я использую необработанную строку для описания таких элементов:
при извлечении предметов и их атрибутов:
Кажется, что это не умнее, чем ответ других людей, но легко понять, что новички могут пустить пыль в глаза.
источник
Я модифицировал решение Вадима следующим образом:
Изменение заключается в map_get, чтобы он не возвращал ошибки, если вы запрашиваете ключ, который не существует, хотя побочным эффектом является то, что он также будет молча игнорировать отсутствующие карты, но это лучше подходит для моего варианта использования, поскольку я просто хотел проверить наличие ключа, чтобы пропустить элементы в цикле.
источник
Поздний ответ, но рассмотрите возможность решения проблемы таким образом, используя встроенную функцию bash, читаемую, как показано в следующем фрагменте кода из сценария межсетевого экрана ufw. Этот подход имеет то преимущество, что используется столько наборов полей с разделителями (а не только 2), сколько требуется. Мы использовали | разделитель, поскольку для спецификаторов диапазона портов может потребоваться двоеточие, например 6001: 6010 .
источник