배열을 반복하여 인덱스와 값을 모두 인쇄


184

나는 이런 식으로하고 싶다 :

foo=( )
foo[0]="bar"
foo[35]="baz"
for((i=0;i<${#foo[@]};i++))
do
    echo "$i: ${foo[$i]}"
done
# Output:
# 0: bar
# 1: 

그런 다음 for를 사용하여 반복하려고했습니다.

foo=( )
foo[0]="bar"
foo[35]="baz"
for i in ${foo[@]}
do
    echo "?: $i"
done
# Output:
# ?: bar
# ?: naz

그러나 여기서는 색인 값을 모릅니다.

나는 네가 다음과 같은 것을 할 수 있다는 것을 안다

foo=( )
foo[0]="bar"
foo[35]="baz"
declare -p foo
# Output:
# declare -a foo='([0]="bar" [35]="baz")'

그러나 다른 방법으로는 할 수 없습니까?

답변:


317

"${!foo[@]}"( reference )가 있는 배열 키를 찾을 수 있습니다.

for i in "${!foo[@]}"; do 
  printf "%s\t%s\n" "$i" "${foo[$i]}"
done

$i, 요소 자체를 통해 액세스 해야하는 동안 인덱스가 포함 됩니다.${foo[$i]}


6
중요한 점은 반복 가능하지만 공백으로 구분 된 단어 목록은 배열 이 아닙니다 . (a b c)배열로 변환하려면 랩핑하십시오 .
Breedly

4
의 사용 [@]및 따옴표는이 "공간이 단어의 목록을 분리"아니에요 의미한다. 개별 키에 공백이 있어도 실제 배열 키 목록을 얻습니다.
glenn jackman 1

@glennjackman 더 자세히 설명해 주실 수 있습니까The use of [@] and double quotes means it's not a "space separated list of words"
Kasun Siyambalapitiya

1
"${foo[@]}"(배열) 변수를 가져 와서 배열로 foo확장하여 요소의 정체성을 유지합니다 (즉, 공백으로 분리하지 않음). 경우 foo=(x 'y z'), 다음 f "${foo[@]}"호출 f두 개의 인수, x하고 'y z'. 메타 데이터는 같은 쿼리 "${!foo[@]}""${#foo[@]}"유사한 조치를 취할 foo배열로.
BallpointBen

정답이지만 그 언급 은 불가피합니다. 이 답변"${!foo[@]}" 은 "어레이에 설정된 모든 인덱스의 목록입니다 "라고 설명합니다 .
pjhsea

17

항상 반복 매개 변수를 사용할 수 있습니다.

ITER=0
for I in ${FOO[@]}
do  
    echo ${I} ${ITER}
    ITER=$(expr $ITER + 1)
done

5
((ITER++))현대 bash에서
David Tonhofer

왜 증가 후인가? 당신은 값만 증가시키기를 원하기 때문에, ((++ ITER))는 당신이 원하는 것을 더 직접적으로 진술합니다. ...
MikeW

3
아니요, "항상"이 아닙니다. 해시는 "구멍"을 가질 수 있으며, 이는 모든 숫자가 색인이 아님을 의미합니다. 귀하의 예에서 $ {ITER}가 항상 $ {I}의 인덱스는 아닙니다.
Marco

10
INDEX=0
for i in $list; do 
    echo ${INDEX}_$i
    let INDEX=${INDEX}+1
done

당신의 대답은 확실히 약간의 가치가 있습니다. stackoverflow.com/help/how-to-answer를 참조하십시오 . 주석은 검색 가능한 컨텐츠를 작성하는 데 도움이됩니다.
J. Chomel

3
이 코드 스 니펫은 문제를 해결할 수 있지만 설명을 포함하면 게시물의 품질을 향상시키는 데 실제로 도움이됩니다. 앞으로 독자들에게 질문에 대한 답변을 제공하므로 해당 사람들이 코드 제안의 이유를 모를 수도 있습니다. 설명 주석으로 코드를 복잡하게 만들지 마십시오. 이렇게하면 코드와 설명의 가독성이 떨어집니다!
kayess

2

bash 4에서는 연관 배열을 사용할 수 있습니다.

declare -A foo
foo[0]="bar"
foo[35]="baz"
for key in "${!foo[@]}"
do
    echo "key: $key, value: ${foo[$key]}"
done

# output
# $ key: 0, value bar.
# $ key: 35, value baz.

bash 3에서 이것은 작동합니다 (zsh에서도 작동합니다).

map=( )
map+=("0:bar")
map+=("35:baz")

for keyvalue in "${map[@]}" ; do
    key=${keyvalue%%:*}
    value=${keyvalue#*:}
    echo "key: $key, value $value."
done

1
users=("kamal" "jamal" "rahim" "karim" "sadia")
index=()
t=-1

for i in ${users[@]}; do
  t=$(( t + 1 ))
  if [ $t -eq 0 ]; then
    for j in ${!users[@]}; do
      index[$j]=$j
    done
  fi
  echo "${index[$t]} is $i"
done

1
이것은 잘못이다! 내부 루프는 쓸모가 없으며 잘못된 결과를 초래할 수 있습니다!
F. Hauri

1

배열 덤프를위한 간단한 한 줄 트릭

공백으로 하나의 값을 추가했습니다.

foo=()
foo[12]="bar"
foo[42]="foo bar baz"
foo[35]="baz"

나는 빨리 덤프 내가 사용하는 배열 또는 연관 배열

이 한 줄 명령 :

paste <(printf "%s\n" "${!foo[@]}") <(printf "%s\n" "${foo[@]}")

렌더링합니다 :

12  bar
35  baz
42  foo bar baz

설명

  • printf "%s\n" "${!foo[@]}"개행으로 구분 된 모든 를 인쇄합니다 .
  • printf "%s\n" "${foo[@]}"개행으로 구분 된 모든 을 인쇄합니다 .
  • paste <(cmd1) <(cmd2)출력 병합 것 cmd1cmd2라인 씩.

튜닝

-d스위치 로 조정할 수 있습니다 .

paste -d : <(printf "%s\n" "${!foo[@]}") <(printf "%s\n" "${foo[@]}")
12:bar
35:baz
42:foo bar baz

또는:

paste -d = <(printf "foo[%s]\n" "${!foo[@]}") <(printf "'%s'\n" "${foo[@]}")
foo[12]='bar'
foo[35]='baz'
foo[42]='foo bar baz'

연관 배열은 동일하게 작동합니다.

declare -A bar=([foo]=snoopy [bar]=nice [baz]=cool [foo bar]='Hello world!')
paste -d = <(printf "bar[%s]\n" "${!bar[@]}") <(printf '"%s"\n' "${bar[@]}")
bar[foo bar]="Hello world!"
bar[foo]="snoopy"
bar[bar]="nice"
bar[baz]="cool"

바꿈 또는 특수 문자 문제

불행히도, 더 이상 작동하지 않는 조건이 하나 이상 있습니다. 변수에 줄 바꿈이 포함될 때 :

foo[17]=$'There is one\nnewline'

명령 paste은 라인별로 병합되므로 출력이 잘못됩니다.

paste -d = <(printf "foo[%s]\n" "${!foo[@]}") <(printf "'%s'\n" "${foo[@]}")
foo[12]='bar'
foo[17]='There is one
foo[35]=newline'
foo[42]='baz'
='foo bar baz'

이 작업을 위해 두 번째 명령 %q대신 따옴표를 사용할 수 있습니다 .%sprintf

paste -d = <(printf "foo[%s]\n" "${!foo[@]}") <(printf "%q\n" "${foo[@]}")

완벽하게 렌더링됩니다 :

foo[12]=bar
foo[17]=$'There is one\nnewline'
foo[35]=baz
foo[42]=foo\ bar\ baz

보낸 사람 man bash:

          %q     causes  printf  to output the corresponding argument in a
                 format that can be reused as shell input.

printf "%q\n" "${var[@]}" 개행 에 대한 나의 투표 는 내 문제였다!
테크노
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.