web-dev-qa-db-fra.com

Boucle dans une variable shell séparée par des virgules

Supposons que j'ai une variable shell Unix comme ci-dessous

variable=abc,def,ghij

Je veux extraire toutes les valeurs (abc, def et ghij) en utilisant une boucle for et passer chaque valeur à une procédure. 

Le script doit permettre d'extraire un nombre arbitraire de valeurs séparées par des virgules à partir de $variable.

55
Ramanathan K

Vous pouvez utiliser le script suivant pour parcourir dynamiquement votre variable, quel que soit le nombre de champs dont elle dispose, à condition qu'elle soit uniquement séparée par des virgules. 

variable=abc,def,ghij
for i in $(echo $variable | sed "s/,/ /g")
do
    # call your procedure/other scripts here below
    echo "$i"
done

Au lieu de l'appel echo "$i" ci-dessus, entre les do et done dans la boucle for, vous pouvez appeler votre procédure proc "$i".


Update : L'extrait ci-dessus fonctionne si la valeur de variable ne contient pas d'espaces. Si vous avez une telle exigence, veuillez utiliser l’une des solutions susceptibles de changer IFS puis d’analyser votre variable.


J'espère que cela t'aides.

71
anacron

Ne pas jouer avec IFS
N'appelle pas de commande externe

variable=abc,def,ghij
for i in ${variable//,/ }
do
    # call your procedure/other scripts here below
    echo "$i"
done

Utilisation de bash string manipulation http://www.tldp.org/LDP/abs/html/string-manipulation.html

88
neric

Si vous définissez un séparateur de champ différent, vous pouvez directement utiliser une boucle for:

IFS=","
for v in $variable
do
   # things with "$v" ...
done

Vous pouvez également stocker les valeurs dans un tableau, puis le parcourir comme indiqué dans Comment fractionner une chaîne dans un délimiteur dans Bash? :

IFS=, read -ra values <<< "$variable"
for v in "${values[@]}"
do
   # things with "$v"
done

Tester

$ variable="abc,def,ghij"
$ IFS=","
$ for v in $variable
> do
> echo "var is $v"
> done
var is abc
var is def
var is ghij

Vous pouvez trouver une approche plus large dans cette solution pour Comment parcourir une liste séparée par des virgules et exécuter une commande pour chaque entrée .

Exemples sur la seconde approche:

$ IFS=, read -ra vals <<< "abc,def,ghij"
$ printf "%s\n" "${vals[@]}"
abc
def
ghij
$ for v in "${vals[@]}"; do echo "$v --"; done
abc --
def --
ghij --
34
fedorqui
#/bin/bash   
TESTSTR="abc,def,ghij"

for i in $(echo $TESTSTR | tr ',' '\n')
do
echo $i
done

Je préfère utiliser tr au lieu de sed, parce qu’il a des problèmes avec les caractères spéciaux comme\r\n dans certains cas.

une autre solution consiste à définir IFS sur certains séparateurs

4
Marek Lisiecki

Une autre solution n'utilisant pas IFS tout en préservant les espaces:

$ var="a bc,def,ghij"
$ while read line; do echo line="$line"; done < <(echo "$var" | tr ',' '\n')
line=a bc
line=def
line=ghij
0
user3071170

Essaye celui-là.

#/bin/bash   
testpid="abc,def,ghij" 
count=`echo $testpid | grep -o ',' | wc -l` # this is not a good way
count=`expr $count + 1` 
while [ $count -gt 0 ]  ; do
     echo $testpid | cut -d ',' -f $i
     count=`expr $count - 1 `
done
0
Karthikeyan.R.S

Voici une solution alternative basée sur le tr n'utilisant pas d'écho, exprimée sous la forme d'une ligne.

for v in $(tr ',' '\n' <<< "$var") ; do something_with "$v" ; done

Je me sens mieux sans écho, mais ce n’est que ma préférence personnelle.

0
6EQUJ5