[bash] Bash에서 해시 테이블을 정의하는 방법은 무엇입니까?
파이썬 사전 과 동등 하지만 Bash 는 무엇입니까 (OS X 및 Linux에서 작동해야 함).
답변
배쉬 4
Bash 4는 기본적으로이 기능을 지원합니다. 확인 스크립트의 hashbang이다 #!/usr/bin/env bash
또는 #!/bin/bash
당신이 사용하게하지 않도록 sh
. 당신이 직접 스크립트를 실행하고 있는지 확인하거나 실행 script
으로 bash script
. (실제로 배쉬와 배쉬 스크립트가 실행되지 않는 일이 될 것입니다 정말 혼란!)
다음을 수행하여 연관 배열을 선언하십시오.
declare -A animals
일반 배열 할당 연산자를 사용하여 요소로 채울 수 있습니다. 예를 들어,의지도를하려는 경우 animal[sound(key)] = animal(value)
:
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
배쉬 3
bash 4 이전에는 연관 배열이 없습니다. 그것들을 모방하기 위해 사용하지 마십시오eval
. 피 eval
가 있기 때문에, 전염병처럼 입니다 쉘 스크립트의 전염병. 가장 중요한 이유는 eval
데이터를 실행 가능한 코드로 취급하기 때문입니다 (다른 많은 이유도 있음).
가장 먼저 : bash 4로 업그레이드하는 것이 좋습니다. 이렇게하면 전체 프로세스가 훨씬 쉬워집니다.
업그레이드 할 수없는 이유 declare
가 있다면 훨씬 안전한 옵션입니다. 데이터를 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 함수 내부를 사용 하면 해당 함수의 범위에 로컬 변수를 생성 하여 전역 배열에 액세스하거나 수정할 수 없습니다. bash 4에서는 선언 -g를 사용하여 전역 변수를 선언 할 수 있지만 bash 4에서는 우선이 해결 방법을 피하면서 연관 배열을 사용할 수 있습니다.
요약:
- bash 4로 업그레이드하고
declare -A
연관 배열에 사용하십시오. declare
업그레이드 할 수없는 경우이 옵션을 사용하십시오 .awk
대신 사용 하고 문제를 피하십시오.
답변
매개 변수 대체가 있지만 PC와 같지 않을 수도 있지만 간접적입니다.
#!/bin/bash
# Array pretending to be a Pythonic dictionary
ARRAY=( "cow:moo"
"dinosaur:roar"
"bird:chirp"
"bash:rock" )
for animal in "${ARRAY[@]}" ; do
KEY="${animal%%:*}"
VALUE="${animal##*:}"
printf "%s likes to %s.\n" "$KEY" "$VALUE"
done
printf "%s is an extinct animal which likes to %s\n" "${ARRAY[1]%%:*}" "${ARRAY[1]##*:}"
BASH 4 방법은 물론 더 좋지만, 해킹이 필요한 경우 … 해킹 만 가능합니다. 비슷한 기술로 배열 / 해시를 검색 할 수 있습니다.
답변
이것이 내가 찾고 있던 것입니다.
declare -A hashmap
hashmap["key"]="value"
hashmap["key2"]="value2"
echo "${hashmap["key"]}"
for key in ${!hashmap[@]}; do echo $key; done
for value in ${hashmap[@]}; do echo $value; done
echo hashmap has ${#hashmap[@]} elements
이것은 bash 4.1.5에서 작동하지 않았습니다.
animals=( ["moo"]="cow" )
답변
다음과 같이 해시 이름을 지정하도록 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”를 사용하여 잘라내거나 awk 또는 sed 또는 값을 검색하는 파이프를 사용하여 가져옵니다.
내가 말했듯이, 그것은 끔찍하게 들리며 느리게 들리고 모든 종류의 불필요한 IO를 해야하는 것처럼 들리지만 실제로는 매우 큰 해시에서도 매우 빠릅니다 (디스크 캐시는 훌륭하고 그렇지 않습니까?). 테이블. 키 고유성을 직접 적용해야합니다. 수백 개의 항목 만 있어도 출력 파일 / 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`
답변
파일 시스템 만 사용하십시오
파일 시스템은 해시 맵으로 사용할 수있는 트리 구조입니다. 해시 테이블은 임시 디렉토리가되고 키는 파일 이름이되고 값은 파일 내용이됩니다. 장점은 거대한 해시 맵을 처리 할 수 있으며 특정 쉘이 필요하지 않다는 것입니다.
해시 테이블 생성
hashtable=$(mktemp -d)
요소 추가
echo $value > $hashtable/$key
요소를 읽으십시오
value=$(< $hashtable/$key)
공연
물론 느리지 만 그렇게 느리지는 않습니다 . SSD와 btrfs를 사용하여 내 컴퓨터에서 테스트했으며 초당 약 3000 개의 요소 읽기 / 쓰기를 수행 합니다.
답변
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
답변
다음 ufw 방화벽 스크립트의 코드 스 니펫에 설명 된대로 bash 내장 읽기 를 사용하는 솔루션을 고려하십시오 . 이 접근 방식은 원하는만큼 많은 구분 된 필드 세트 (2 개가 아닌)를 사용하는 이점이 있습니다. 우리는 | 포트 범위 지정자에는 콜론 (예 : 6001 : 6010) 이 필요할 수 있으므로 분리 문자 입니다.
#!/usr/bin/env bash
readonly connections=(
'192.168.1.4/24|tcp|22'
'192.168.1.4/24|tcp|53'
'192.168.1.4/24|tcp|80'
'192.168.1.4/24|tcp|139'
'192.168.1.4/24|tcp|443'
'192.168.1.4/24|tcp|445'
'192.168.1.4/24|tcp|631'
'192.168.1.4/24|tcp|5901'
'192.168.1.4/24|tcp|6566'
)
function set_connections(){
local range proto port
for fields in ${connections[@]}
do
IFS=$'|' read -r range proto port <<< "$fields"
ufw allow from "$range" proto "$proto" to any port "$port"
done
}
set_connections