J'ai quelque chose dans bash
comme
myArray=('red' 'orange' 'green')
Et je voudrais faire quelque chose comme
echo ${myArray['green']}
Ce qui dans ce cas produirait 2
. Est-ce réalisable?
Cela va le faire:
#!/bin/bash
my_array=(red orange green)
value='green'
for i in "${!my_array[@]}"; do
if [[ "${my_array[$i]}" = "${value}" ]]; then
echo "${i}";
fi
done
Évidemment, si vous convertissez cela en une fonction (par exemple, get_index ()), vous pouvez le rendre générique
Vous devez déclarer votre tableau avant utilisation avec
declare -A myArray
myArray=([red]=1 [orange]=2 [green]=3)
echo ${myArray['orange']}
Non. Vous pouvez uniquement indexer un tableau simple avec un entier dans bash
. Les tableaux associatifs (introduits dans bash
4) peuvent être indexés par des chaînes. Cependant, ils ne fournissent pas le type de recherche inversée que vous demandez, sans tableau associatif spécialement construit.
$ declare -A myArray
$ myArray=([red]=0 [orange]=1 [green]=2)
$ echo ${myArray[green]}
2
Il y a aussi un moyen astucieux:
echo ${myArray[@]/green//} | cut -d/ -f1 | wc -w | tr -d ' '
Et vous obtenez 2 Voici des références
J'aime cette solution:
let "n=(`echo ${myArray[@]} | tr -s " " "\n" | grep -n "green" | cut -d":" -f 1`)-1"
La variable n contiendra le résultat!
C’est juste une autre façon d’initialiser un tableau associatif comme le montre chepner . N'oubliez pas que vous devez explicitement declare
ou typset un tableau associatif avec l'attribut -A
.
i=0; declare -A myArray=( [red]=$((i++)) [orange]=$((i++)) [green]=$((i++)) )
echo ${myArray[green]}
2
Cela supprime le besoin de coder en dur les valeurs et rend peu probable que vous obteniez des doublons.
Si vous avez beaucoup de valeurs à ajouter, cela peut aider de les mettre sur des lignes séparées.
i=0; declare -A myArray;
myArray+=( [red]=$((i++)) )
myArray+=( [orange]=$((i++)) )
myArray+=( [green]=$((i++)) )
echo ${myArray[green]}
2
Supposons que vous vouliez un tableau de chiffres et de lettres minuscules (par exemple: pour une sélection de menu), vous pouvez également faire quelque chose comme ceci.
declare -a mKeys_1=( {{0..9},{a..z}} );
i=0; declare -A mKeys_1_Lookup; eval mKeys_1_Lookup[{{0..9},{a..z}}]="$((i++))";
Si vous courez alors
echo "${mKeys_1[15]}"
f
echo "${mKeys_1_Lookup[f]}"
15
Cela pourrait fonctionner pour les tableaux,
my_array=(red orange green)
echo "$(printf "%s\n" "${my_array[@]}")" | grep -n '^orange$' | sed 's/:orange//'
Sortie:
2
Si vous voulez trouver un index d’en-tête dans un fichier tsv,
head -n 1 tsv_filename | sed 's/\t/\n/g' | grep -n '^header_name$' | sed 's/:header_name//g'
Un autre one-liner délicat:
index=$((-1 + 10#0$(IFS=$'\n' echo "${my_array[*]}" | grep --line-number --fixed-strings -- "$value" | cut -f1 -d:)))
fonctionnalités:
-1
si non trouvémises en garde:
value
soit non videExplications en le décomposant en ordre d'exécution:
IFS=$'\n' echo "${my_array[*]}"
définir le séparateur d'expansion de tableau (IFS
) sur une nouvelle ligne char & développer le tableau
grep --line-number --fixed-strings -- "$value"
grep pour un match:
--line-number
ou -n
)--fixed-strings
ou -F
; désactive regex)autoriser les éléments commençant par -
(--
)
cut -f1 -d:
extraire uniquement le numéro de ligne (le format est <line_num>:<matched line>
)
$((-1 + 10#0$(...)))
soustrayez 1 puisque les numéros de ligne sont indexés 1 et les tableaux indexés 0
si $(...)
ne correspond pas:
0
est utilisée (10#0
)$(...)
correspond à: 10#0
; i.e. 10#02
, 10#09
, 10#014
, etc.10#
force les nombres base-10/décimaux au lieu d'octalUtilisation de awk
au lieu de grep
, cut
& bash arithmetic:
IFS=$'\n'; awk "\$0 == \"${value//\"/\\\"}\" {print NR-1}" <<< "${my_array[*]}"
fonctionnalités:
mises en garde:
si non trouvéExplications en le décomposant en ordre d'exécution:
IFS=$'\n' [...] <<< "${my_array[*]}"
définir le séparateur d'expansion de tableau (IFS
) sur une nouvelle ligne char & développer le tableau
awk "\$0 == \"${value//\"/\\\"}\" {print NR-1}"
faire correspondre la ligne entière et imprimer le numéro de ligne indexé 0
${value//\"/\\\"}
remplace les guillemets dans $value
par les versions échappéesUn peu plus concis et fonctionne dans Bash 3.x:
my_array=(red orange green)
value='green'
for i in "${!my_array[@]}"; do
[[ "${my_array[$i]}" = "${value}" ]] && break
done
echo $i
En zsh tu peux faire
xs=( foo bar qux )
echo ${xs[(ie)bar]}
voir zshparam (1) sous-section Indicateurs sur l'indice
Solution simple:
my_array=(red orange green)
echo ${my_array[*]} | tr ' ' '\n' | awk '/green/ {print NR-1}'