Looping over arrays, printing both index and value

前端 未结 6 1937
无人及你
无人及你 2020-12-07 07:35

I want to do something like this:

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


        
相关标签:
6条回答
  • 2020-12-07 07:59
    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
    
    0 讨论(0)
  • 2020-12-07 08:09

    In bash 4, you can use associative arrays:

    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.
    

    In bash 3, this works (also works in zsh):

    map=( )
    map+=("0:bar")
    map+=("35:baz")
    
    for keyvalue in "${map[@]}" ; do
        key=${keyvalue%%:*}
        value=${keyvalue#*:}
        echo "key: $key, value $value."
    done
    
    0 讨论(0)
  • 2020-12-07 08:12
    INDEX=0
    for i in $list; do 
        echo ${INDEX}_$i
        let INDEX=${INDEX}+1
    done
    
    0 讨论(0)
  • 2020-12-07 08:14

    Simple one line trick for dumping array

    I've added one value with spaces:

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

    I, for quickly dump bash arrays or associative arrays I use

    This one line command:

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

    Will render:

    12  bar
    35  baz
    42  foo bar baz
    

    Explained

    • printf "%s\n" "${!foo[@]}" will print all keys separated by a newline,
    • printf "%s\n" "${foo[@]}" will print all values separated by a newline,
    • paste <(cmd1) <(cmd2) will merge output of cmd1 and cmd2 line by line.

    Tunning

    This could be tunned by -d switch:

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

    or even:

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

    Associative array will work same:

    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"
    

    Issue with newlines or special chars

    Unfortunely, there is at least one condition making this not work anymore: when variable do contain newline:

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

    Command paste will merge line-by-line, so output will become wrong:

    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'
    

    For this work, you could use %q instead of %s in second printf command (and whipe quoting):

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

    Will render perfect:

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

    From man bash:

              %q     causes  printf  to output the corresponding argument in a
                     format that can be reused as shell input.
    
    0 讨论(0)
  • 2020-12-07 08:21

    you can always use iteration param:

    ITER=0
    for I in ${FOO[@]}
    do  
        echo ${I} ${ITER}
        ITER=$(expr $ITER + 1)
    done
    
    0 讨论(0)
  • 2020-12-07 08:23

    You would find the array keys with "${!foo[@]}" (reference), so:

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

    Which means that indices will be in $i while the elements themselves have to be accessed via ${foo[$i]}

    0 讨论(0)
提交回复
热议问题