Как определить хеш-таблицы в Bash?

insert into customer_keyskill(customerID, keySkillID)
select  2,1 from dual
where not exists ( 
    select  customerID  from customer_keyskill 
    where customerID = 2 
    and keySkillID = 1 )
490
задан codeforester 17 February 2017 в 05:26
поделиться

5 ответов

Bash 4

Bash 4 изначально поддерживает эту функцию. Убедитесь, что хэшбэнг вашего скрипта - #! / Usr / bin / env bash или #! / Bin / bash , чтобы вы не использовали sh . Убедитесь, что вы либо выполняете свой сценарий напрямую, либо выполняете сценарий с помощью сценария bash . (На самом деле не выполнение сценария Bash с Bash происходит , и действительно сбивает с толку!)

Вы объявляете ассоциативный массив, выполнив:

declare -A animals

Вы можете заполнить его с элементами, использующими обычный оператор присваивания массива. Например, если вы хотите получить карту животное [звук (ключ)] = животное (значение) :

animals=( ["moo"]="cow" ["woof"]="dog")

или объединить их:

declare -A animals=( ["moo"]="cow" ["woof"]="dog")

Затем используйте их, как обычные массивы. Используйте animals ['key'] = 'value' , чтобы установить значение, "$ {animals [@]}" , чтобы развернуть значения, и "$ {! Animals" [@]} " (обратите внимание на ! ), чтобы раскрыть ключи. Не забудьте процитировать их:

echo "${animals[moo]}"
for sound in "${!animals[@]}"; do echo "$sound - ${animals[$sound]}"; done

Bash 3

До bash 4 у вас не было ассоциативных массивов. Не используйте eval для имитации . Избегайте eval как чумы, потому что это чума сценариев оболочки. Самая важная причина в том, что eval обрабатывает ваши данные как исполняемый код (есть и много других причин).

Прежде всего : подумайте об обновлении до bash 4. Это значительно упростит вам весь процесс.

Если есть причина, по которой вы не можете выполнить обновление, объявите гораздо более безопасным вариантом. Он не оценивает данные, как код bash, как eval , и, как таковой, не позволяет с такой легкостью внедрять произвольный код.

Давайте подготовим ответ, введя понятия:

Во-первых, косвенное обращение.

$ animals_moo=cow; sound=moo; i="animals_$sound"; echo "${!i}"
cow

Во-вторых, declare :

$ sound=moo; animal=cow; declare "animals_$sound=$animal"; echo "$animals_moo"
cow

Объедините их:

# Set a value:
declare "array_$index=$value"

# Get a value:
arrayGet() { 
    local array=$1 index=$2
    local i="${array}_$index"
    printf '%s' "${!i}"
}

Давайте использовать его:

$ sound=moo
$ animal=cow
$ declare "animals_$sound=$animal"
$ arrayGet animals "$sound"
cow

Примечание: declare нельзя поместить в функцию. Любое использование declare внутри функции bash переводит создаваемую им переменную local в область действия этой функции, что означает, что мы не можем получить доступ или изменить глобальные массивы с ее помощью. (В bash 4 вы можете использовать declare -g для объявления глобальных переменных - но в bash 4 вы можете в первую очередь использовать ассоциативные массивы, избегая этого обходного пути.)

Резюме:

  • Обновите до bash 4 и используйте объявить -A для ассоциативных массивов.
  • Используйте параметр объявить , если вы не можете выполнить обновление.
  • Рассмотрите возможность использования вместо него awk и вообще избегайте проблемы.
863
ответ дан 22 November 2019 в 22:29
поделиться
hput () {
  eval hash"$1"='$2'
}

hget () {
  eval echo '${hash'"$1"'#hash}'
}
hput France Paris
hput Netherlands Amsterdam
hput Spain Madrid
echo `hget France` and `hget Netherlands` and `hget Spain`

$ sh hash.sh
Paris and Amsterdam and Madrid
14
ответ дан 22 November 2019 в 22:29
поделиться

Вы можете дополнительно изменить интерфейс hput () / hget (), чтобы вы назвали хеши следующим образом:

hput() {
    eval "$1""$2"='$3'
}

hget() {
    eval echo '${'"$1$2"'#hash}'
}

, а затем

hput capitals France Paris
hput capitals Netherlands Amsterdam
hput capitals Spain Madrid
echo `hget capitals France` and `hget capitals Netherlands` and `hget capitals Spain`

Это позволяет вы определяете другие карты, которые не конфликтуют (например, 'rcapitals', который выполняет поиск страны по столице). Но в любом случае, я думаю, вы обнаружите, что все это довольно ужасно с точки зрения производительности.

Если вам действительно нужен быстрый поиск хэша, есть ужасный, ужасный прием, который действительно работает очень хорошо. Это так: запишите свои ключи / значения во временный файл, по одному на строку, затем используйте 'grep "^ $ key"', чтобы вывести их, используя каналы с cut, awk или sed или что-то еще, чтобы получить значения.

Как я уже сказал, это звучит ужасно, и похоже, что он должен быть медленным и выполнять всевозможные ненужные операции ввода-вывода, но на практике это очень быстро (кеш-диск - это круто, не так ли?), Даже для очень большие хеш-таблицы. Вы должны сами обеспечить уникальность ключа и т. Д. Даже если у вас всего несколько сотен записей, комбинация выходной файл / grep будет немного быстрее - по моему опыту, в несколько раз быстрее. К тому же память съедает меньше.

Вот один из способов сделать это:

hinit() {
    rm -f /tmp/hashmap.$1
}

hput() {
    echo "$2 $3" >> /tmp/hashmap.$1
}

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

hinit capitals
hput capitals France Paris
hput capitals Netherlands Amsterdam
hput capitals Spain Madrid

echo `hget capitals France` and `hget capitals Netherlands` and `hget capitals Spain`
24
ответ дан 22 November 2019 в 22:29
поделиться

До bash 4 не было хорошего способа использовать ассоциативные массивы в bash. Лучше всего использовать интерпретируемый язык, который действительно поддерживает такие вещи, как awk. С другой стороны, bash 4 их поддерживает .

Что касается less хороших способов в bash 3, вот ссылка, которая может помочь: http://mywiki.wooledge.org/BashFAQ/006

2
ответ дан 22 November 2019 в 22:29
поделиться

Две вещи: вы можете использовать память вместо / tmp в любом ядре 2.6, используя / dev / shm (Redhat), другие дистрибутивы могут отличаться. Также hget может быть повторно реализован с помощью read следующим образом:

function hget {

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

Кроме того, предполагая, что все ключи уникальны, return замыкает цикл чтения и предотвращает необходимость чтения всех записей. Если в вашей реализации могут быть повторяющиеся ключи, просто не учитывайте return. Это экономит затраты на чтение и разветвление как grep, так и awk. Использование / dev / shm для обеих реализаций дало следующее: time hget для хэша из 3 записей, ищущего последнюю запись:

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

Read / echo:

$ time echo $(hget FD oracle)
3

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

при многократных вызовах я никогда не видел меньше, чем улучшение на 50%. Все это можно отнести к разветвленной работе из-за использования / dev / shm .

2
ответ дан 22 November 2019 в 22:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: