배열 배열에서 반복할 배열을 선택하는 방법은 무엇입니까?

배열 배열에서 반복할 배열을 선택하는 방법은 무엇입니까?
#!/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가 그 중 하나를 선택할 수 있도록 하고 싶습니다. 사용자 입력 후 스크립트는 선택한 배열의 각 요소를 인쇄합니다. selectarray() 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

"키"를 "값"으로 매핑해야 합니다. 여기서 "값"은 문자열 목록이고 "키" ARGENTBIENETRE...

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

관련 정보