bash 循环数组,打印索引和值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6723426/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 20:46:10  来源:igfitidea点击:

Looping over arrays, printing both index and value

bash

提问by Tyilo

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: bar
# 1: 

Then i tried to loop through it using for in:

然后我尝试使用 for in 循环遍历它:

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

but here I don't know the index value.

但在这里我不知道索引值。

I know you could something like

我知道你可以像

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

but, can't you do it in another way?

但是,你不能换一种方式吗?

回答by glenn Hymanman

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

你会用"${!foo[@]}"( reference)找到数组键,所以:

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

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

这意味着索引将在,$i而元素本身必须通过访问${foo[$i]}

回答by Eyal Ch

you can always use iteration param:

你总是可以使用迭代参数:

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

回答by Aruy Aruy

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

回答by mattmc3

In bash 4, you can use associative arrays:

在 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.

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

在 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

回答by F. Hauri

Simple one linetrick 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 basharrays or associative arraysI use

我,为了快速转储我使用的bash数组或关联数组

This one line command:

这一行命令:

paste <(printf "%s\n" "${!foo[@]}") <(printf "%s\n" "${foo[@]}")
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 keysseparated by a newline,
  • printf "%s\n" "${foo[@]}"will print all valuesseparated by a newline,
  • paste <(cmd1) <(cmd2)will merge output of cmd1and cmd2line by line.
  • printf "%s\n" "${!foo[@]}"将打印由换行符分隔的所有
  • printf "%s\n" "${foo[@]}"将打印由换行符分隔的所有
  • paste <(cmd1) <(cmd2)将逐行合并cmd1和 的输出cmd2

Tunning

调谐

This could be tunned by -dswitch:

这可以通过-d开关调整:

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 newlinesor 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 pastewill merge line-by-line, so output will become wrong:

命令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'

For this work, you could use %qinstead of %sin second printfcommand (and whipe quoting):

对于这项工作,您可以使用%q而不是%s在第二个printf命令中(和whipe 引用):

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:

来自man bash

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

回答by code4mk

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