programing

어레이를 루프하여 인덱스와 값을 모두 인쇄

testmans 2023. 4. 15. 08:30
반응형

어레이를 루프하여 인덱스와 값을 모두 인쇄

나는 다음과 같은 것을 하고 싶다.

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")'

다른 방법은 없나요?

어레이 키는 다음과 같이 표시됩니다."${!foo[@]}"(참조) 그래서:

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

그 말은 즉, 지표가 그 안에 있을 거라는 거죠$i요소 자체에 액세스 할 필요가 있는 한편,${foo[$i]}

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

ITER=0
for I in ${FOO[@]}
do  
    echo ${I} ${ITER}
    ITER=$(expr $ITER + 1)
done
INDEX=0
for i in $list; do 
    echo ${INDEX}_$i
    let INDEX=${INDEX}+1
done

어레이 덤프를 위한 간단한 줄 기술

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

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

사용하는 bash 어레이 또는 관련 어레이의 덤프용

다음 한 줄 명령어:

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)의 출력을 병합합니다.cmd1그리고.cmd2한 줄 한 줄

튜닝

이것은, 에 의해서 조정될 수 있습니다.-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"

바꿈 또는 특수 문자 문제

안타깝게도 이 기능이 더 이상 작동하지 않는 조건이 하나 이상 있습니다. 변수에 newline이 포함되어 있는 경우:

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

명령어paste는 행별로 Marge되므로 출력이 잘못됩니다.

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대신%s두 번째로printf명령어(및 휘핑 견적):

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.

또는 다음 기능을 사용합니다.

dumpArray() {
    local -n _ary=$1
    local _idx
    local -i _idlen=0
    for _idx in "${!_ary[@]}"; do
        _idlen=" ${#_idx} >_idlen ? ${#_idx} : _idlen "
    done
    for _idx in "${!_ary[@]}"; do
        printf "%-*s: %s\n" "$_idlen" "$_idx" \
            "${_ary["$_idx"]//$'\n'/$'\n\e['${_idlen}C: }"
    done
}

그럼 지금:

dumpArray foo
12: bar
17: There is one
  : newline
35: baz
42: foo bar baz

dumpArray bar
foo    : snoopy
bar    : nice
baz    : cool
foo bar: Hello world!

UTF-8 형식의 출력에 대해서

UTF-8 문자열 길이에서 다음을 추가합니다.

strU8DiffLen() { local chLen=${#1} LANG=C LC_ALL=C;return $((${#1}-chLen));}

그리고나서

dumpArray() {
    local -n _ary=$1
    local _idx
    local -i _idlen=0
    for _idx in "${!_ary[@]}"; do
        _idlen=" ${#_idx} >_idlen ? ${#_idx} : _idlen "
    done
    for _idx in "${!_ary[@]}"; do
        strU8DiffLen "$_idx"
        printf "%-*s: %s\n" $(($?+$_idlen)) "$_idx" \
            "${_ary["$_idx"]//$'\n'/$'\n\e['${_idlen}C: }"
    done
}

데모:

foo=([12]="bar" [42]="foo bar baz" [35]="baz")
declare -A bar=([foo]=snoopy [bar]=nice [baz]=cool [foo bar]='Hello world!')

foo[17]=$'There is one\nnewline'
LANG=fr.UTF-8 printf -v bar[déjà]  $'%(%a %d %b\n%Y\n%T)T' -1

dumpArray bar
déjà   : ven 24 déc
       : 2021
       : 08:36:05
foo    : snoopy
bar    : nice
baz    : cool
foo bar: Hello world!

dumpArray foo
12: bar
17: There is one
  : newline
35: baz
42: foo bar baz

bash 4에서는 다음과 같은 연관 어레이를 사용할 수 있습니다.

declare -A foo
foo[0]="bar"
foo[35]="baz"

# for Zsh, change this to: for key in "${(k)foo[@]}"
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
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

언급URL : https://stackoverflow.com/questions/6723426/looping-over-arrays-printing-both-index-and-value

반응형