Je veux faire quelque chose comme ça:
foo=( )
foo[0]="bar"
foo[35]="baz"
for((i=0;i<${#foo[@]};i++))
do
echo "$i: ${foo[$i]}"
done
# Output:
# 0: bar
# 1:
Ensuite, j'ai essayé de le parcourir en utilisant for in:
foo=( )
foo[0]="bar"
foo[35]="baz"
for i in ${foo[@]}
do
echo "?: $i"
done
# Output:
# ?: bar
# ?: naz
mais ici je ne connais pas la valeur de l'indice.
Je sais que tu pourrais quelque chose comme
foo=( )
foo[0]="bar"
foo[35]="baz"
declare -p foo
# Output:
# declare -a foo='([0]="bar" [35]="baz")'
mais, ne pouvez-vous pas le faire d'une autre manière?
(a b c)
pour le convertir en tableau.[@]
et de guillemets doubles signifie qu'il ne s'agit pas d'une "liste de mots séparés par des espaces". Vous obtenez la liste des clés de tableau réelles, même si les clés individuelles contiennent des espaces.The use of [@] and double quotes means it's not a "space separated list of words"
"${foo[@]}"
prend la variable (tableau)foo
et l'étend comme un tableau, en conservant l'identité de ses éléments, c'est-à-dire en ne les divisant pas sur des espaces. Sifoo=(x 'y z')
, alorsf "${foo[@]}"
appellef
avec deux arguments,x
et'y z'
. Les requêtes de métadonnées aiment"${!foo[@]}"
et"${#foo[@]}"
agissent de la même manièrefoo
comme un tableau."${!foo[@]}"
est la liste de tous les index définis dans le tableau".vous pouvez toujours utiliser le paramètre d'itération:
ITER=0 for I in ${FOO[@]} do echo ${I} ${ITER} ITER=$(expr $ITER + 1) done
la source
((ITER++))
in modern bashINDEX=0 for i in $list; do echo ${INDEX}_$i let INDEX=${INDEX}+1 done
la source
Dans bash 4, vous pouvez utiliser des tableaux associatifs:
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.
Dans bash 3, cela fonctionne (fonctionne également dans zsh):
map=( ) map+=("0:bar") map+=("35:baz") for keyvalue in "${map[@]}" ; do key=${keyvalue%%:*} value=${keyvalue#*:} echo "key: $key, value $value." done
la source
Astuce simple en une ligne pour vider un tableau
J'ai ajouté une valeur avec les espaces:
foo=() foo[12]="bar" foo[42]="foo bar baz" foo[35]="baz"
Moi, pour vider rapidement frappertableaux ou tableaux associatifs que j'utilise
Cette commande en une ligne:
paste <(printf "%s\n" "${!foo[@]}") <(printf "%s\n" "${foo[@]}")
Rendra:
Expliqué
printf "%s\n" "${!foo[@]}"
imprimera toutes les clés séparées par une nouvelle ligne ,printf "%s\n" "${foo[@]}"
affichera toutes les valeurs séparées par une nouvelle ligne ,paste <(cmd1) <(cmd2)
fusionnera la sortie decmd1
etcmd2
ligne par ligne.Tunning
Cela pourrait être réglé par le
-d
commutateur:paste -d : <(printf "%s\n" "${!foo[@]}") <(printf "%s\n" "${foo[@]}") 12:bar 35:baz 42:foo bar baz
ou même:
paste -d = <(printf "foo[%s]\n" "${!foo[@]}") <(printf "'%s'\n" "${foo[@]}") foo[12]='bar' foo[35]='baz' foo[42]='foo bar baz'
Le tableau associatif fonctionnera de la même manière:
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"
Problème avec les sauts de ligne ou les caractères spéciaux
Malheureusement, il y a au moins une condition qui empêche cela de fonctionner: lorsque la variable contient une nouvelle ligne:
foo[17]=$'There is one\nnewline'
La commande
paste
fusionnera ligne par ligne, donc la sortie deviendra incorrecte: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'
Pour ce travail, vous pouvez utiliser à la
%q
place de%s
dans la deuxièmeprintf
commande (et whipe quote):paste -d = <(printf "foo[%s]\n" "${!foo[@]}") <(printf "%q\n" "${foo[@]}")
Rendra parfait:
foo[12]=bar foo[17]=$'There is one\nnewline' foo[35]=baz foo[42]=foo\ bar\ baz
De
man bash
:la source
printf "%q\n" "${var[@]}"
nouvelle ligne était mon problème!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
la source