#!/usr/bin/bash
ARGENT=("Nous devons économiser de l'argent."
"Je dois économiser de l'argent.")
BIENETRE=("Comment vas-tu?" "Tout va bien ?")
aoarrs=("${ARGENT}" "${BIENETRE}")
select arr in "${aoarrs[@]}"; do
for el in "${arr[@]}"; do
echo "$el"
done
break
done
나는 이 스크립트가 배열 이름을 사용자에게 인쇄하여 ARGENT
사용자 BIENETRE
가 그 중 하나를 선택할 수 있도록 하고 싶습니다. 사용자 입력 후 스크립트는 선택한 배열의 각 요소를 인쇄합니다. select
array() of arrays에서 반복할 배열을 선택하고 싶습니다 aoarrs
. 내가 select를 사용하려는 이유는 실제 세계에서 배열 배열에 두 개 이상의 배열이 있을 수 있기 때문입니다. 어떻게 해야 하나요?
답변1
배열을 저장합니다.이름에서 aoarrs
다음을 선언합니다.이름 참조선택한 이름으로:
ARGENT=("Nous devons économiser de l'argent."
"Je dois économiser de l'argent.")
BIENETRE=("Comment vas-tu?" "Tout va bien ?")
aoarrs=(ARGENT BIENETRE)
PS3='Which array? '
select arr in "${aoarrs[@]}"; do
[[ $arr ]] || continue
declare -n ref=$arr
for i in "${!ref[@]}"; do
printf '%d\t%s\n' $i "${ref[i]}"
done
break
done
달리는 모습은 다음과 같습니다.
1) ARGENT
2) BIENETRE
Which array? 3
Which array? 4
Which array? 5
Which array? 2
0 Comment vas-tu?
1 Tout va bien ?
답변2
"키"를 "값"으로 매핑해야 합니다. 여기서 "값"은 문자열 목록이고 "키" ARGENT
는 BIENETRE
...
aoarrs
이 배열을 연관 배열로 사용할 수 있으므로 올바른 경로에 있습니다 .
declare -A aoarrs
aoarrs[ARGENT]=$ARGENT
aoarrs[BIENETRE]=$BIENETRE
그런 다음 비슷한 방법을 사용하여 해당 배열의 모든 키를 반복합니다 for key in ${!aoarrs[@]}…
.
슬프게도, 어떤 이유로 든 bash는 목록을 이러한 연관 배열의 요소로 허용하지 않습니다.
그래서 상황이 좋지 않습니다. 예를 들어 목록의 요소를 예약된 문자와 연결하여 나중에 분할할 수 있습니다(이것은 문자열에 모든 문자를 포함할 수 없거나 이스케이프를 시작해야 한다는 의미이므로 어리석은 일입니다). 자신만의 함수 만들기 문자열 목록을 가져와 이를 큰 배열에 추가한 다음 해당 컨테이너에 자신만의 연관 조회 함수를 구현합니다. (이것은 어리석은 일입니다. 속도가 느릴 뿐만 아니라 직접 작성해야 합니다. 상대적으로 큰 공간 상대적으로 많은 양의 코드) 부적절한 언어). 나빠 보일 것입니다. 다음은 너무 보기 흉하고 머릿속에서 지워야 하지만 더 이상 다루고 싶지 않기 때문에 테스트하지 않고 적어 놓은 예입니다.
#!/bin/bash
###############################
# UNTESTED STUFF #
# If you think this code is #
# acceptable, consider doing #
# something good for yourself #
# once in a while #
###############################
declare -A index
declare -A lengths
declare -a storage
# Adds an entry to our our custom container
#
# Usage:
# add_key_values KEY "list element 1" "list element 2" …
function add_key_values() {
local key="$1"
shift
local -n valuelist=$@
# get the length of the passed list, to save it
local lengthlist=${#valuelist[@]}
# get the end of the current storage, that's where we start adding
# our list
local start_index=${#storage[@]}
# finally, actually store the list items in the storage
for item in "${valuelist[@]}"; do
storage+=("${item}")
done
lengths["${key}"]=$lengthlist
index["${key}"]=$start_index
}
# Retrieve a list from the storage
# Sadly, bash is not a proper programming language, because what it calls
# "functions" don't do the one thing that a function needs to do:
# return a value for an argument. There's just no "return" mechanism in bash.
#
# Returns an empty list if the key wasn't found.
#
# So, after sobbing a bit, we just say
# Usage:
# get_values $key
# Overwrites the `ret_val` variable with the list that was saved earlier
function get_values() {
# prepare ret_val
declare -g -a ret_val=()
local key=$1
# We return (with ret_val empty) if key isn't present
# frigging bash doesn't have a "is key present in associative array" function…
# so this is the workaround to check whether there's $key in $index.
# seriously.
local teststring
teststring="$(printf 'index[%s]' "${key}")"
# you need quite modern bash to even get the "is defined" -v test
[[ -v "${teststring}" ]] || return
# let's get all the elements from storage and append them to ret_val
local start=${index[$key]}
local length=${lengths[$key]}
for idx in $(seq $(( start - 1 )) $((start - 1 + length)) ); do
ret_val+=("${storage[idx]}")
done
}
####################
# EXAMPLE USAGE
####################
add_key_values "ARGENT" "Nous devons économiser de l'argent." "Je dois économiser de l'argent."
add_key_values "BIENETRE" ("Comment vas-tu?" "Tout va bien ?")
for key in ${!index[@]}; do
echo "the list for value $key contains"
get_values "${key}"
for element in ${ret_val[@]}; do
echo "element: ${element}"
done
done
다음 옵션은 마술적이며 이름으로 변수를 "간접적으로 처리"하기 위해 eval
. 이것은 사악하고 어리석은 일이며 여기에는 "그 지점에 도달하면 bash 대신 적절한 프로그래밍 언어를 사용하십시오"를 제안하는 게시물이 많이 있습니다.
나는 이것에 동의한다: 전체 문제는 실제로 네 줄의 Python으로 수행할 수 있습니다. 처음 두 줄은 "ARGENT" 및 "BIENETRE"와 해당 목록을 dict
. 범용 언어, 연관 배열은 그렇게 나쁘지 않습니다.
답변3
변수 이름만 포함하는 배열을 생성합니다.
aoarrs=(ARGENT BIENETRE)
while :; do
select arr in "${aoarrs[@]}" quit; do
declare -n ref=$arr
case $arr in
quit)
break 2;;
*)
select item in "${ref[@]}"; do
echo $item
break
done;;
esac
break
done
done
declare -n ref=$arr
-해당 값으로 명명된 변수를 참조합니다.
break 2
-2개의 닫힌 루프를 끊습니다.
답변4
ksh93(셸 bash가 에뮬레이트하려고 시도하는)에서는 연관 배열이 배열(무엇보다도)을 값으로 사용할 수 있는 경우가 더 쉬울 것입니다.
#! /bin/ksh -
typeset -A all=(
[argent]=(
"Nous devons économiser de l'argent."
"Je dois économiser de l'argent."
)
[bien-être]=(
"Comment vas-tu?"
"Tout va bien ?"
)
)
select topic in "${!all[@]}"; do
for sentence in "${all[$topic][@]}"; do
print -r -- "$sentence"
done
break
done