2908 votes

Comment puis-je diviser une chaîne sur un délimiteur dans le bash?

Comment puis-je diviser une chaîne basée sur un délimiteur dans le Bash?

J'ai cette chaîne stockée dans une variable:

IN="bla@some.com;john@home.com"

Maintenant, je souhaite partager les cordes par des ';' délimiteur de sorte que j'ai

ADDR1="bla@some.com"
ADDR2="john@home.com"

Je n'ai pas forcément besoin de l' ADDR1 et ADDR2 variables. Si ils sont des éléments d'un tableau qui est encore mieux.

Edit: Après les suggestions de réponses ci-dessous, j'ai fini avec la suivante, qui est ce que je recherchais:

#!/usr/bin/env bash

IN="bla@some.com;john@home.com"

arr=$(echo $IN | tr ";" "\n")

for x in $arr
do
    echo "> [$x]"
done

sortie:

> [bla@some.com]
> [john@home.com]

Edit2: Il y a une solution avec le réglage de Internal_field_separator (FI)';'. Je ne suis pas sûr de ce qui s'est passé avec cette réponse, comment voulez-vous réinitialiser IFS par défaut?

Edit3: RE: IFS solution, j'ai essayé et ça marche, je garde les vieux IFS, puis le restaurer:

IN="bla@some.com;john@home.com"

OIFS=$IFS
IFS=';'
arr2=$IN
for x in $arr2
do
    echo "> [$x]"
done

IFS=$OIFS

BTW, quand j'ai essayé

arr2=($IN) 

J'ai seulement eu la première chaîne lors de l'impression en boucle, sans crochets autour de l' $IN il fonctionne.

1674voto

Johannes Schaub - litb Points 256113

Vous pouvez définir l' interne séparateur de champ (IFS) de la variable, puis le laisser analyser dans un tableau. Lorsque cela se produit dans une commande, puis la cession d' IFS n'a lieu à ce seul commandement de l'environnement ( read ). Il analyse ensuite l'entrée en fonction de l' IFS valeur de la variable dans un tableau, que l'on peut parcourir.

IFS=';' read -ra ADDR <<< "$IN"
for i in "${ADDR[@]}"; do
    # process "$i"
done

Il analyse une ligne d'éléments séparés par des ;, et de les pousser dans un tableau. Des trucs pour le traitement de l'ensemble de l' $IN, à chaque fois qu'une ligne d'entrée séparés par ;:

 while IFS=';' read -ra ADDR; do
      for i in "${ADDR[@]}"; do
          # process "$i"
      done
 done <<< "$IN"

1596voto

palindrom Points 3028

Prises de Bash shell script split tableau:

IN="bla@some.com;john@home.com"
arrIN=(${IN//;/ })

381voto

Chris Lutz Points 34157

Si vous n'avez pas l'esprit de les traiter immédiatement, je tiens à faire ce:

for i in $(echo $IN | tr ";" "\n")
do
  # process
done

Vous pouvez utiliser ce genre de boucle d'initialiser un tableau, mais il y a probablement un moyen plus facile de le faire. Espérons que cela aide, cependant.

358voto

F. Hauri Points 5893

Compatible répondre

Pour cela DONC, la question, il y a déjà beaucoup de différentes façon de le faire en . Mais bash autant de spécial , donc appelé bashism qui fonctionnent bien, mais qui ne fonctionne pas dans tout autre . En particulier, les tableaux, tableau associatif, et le modèle de substitution sont de la pure bashisms et peuvent ne pas fonctionner sous d'autres coquilles.

Sur ma Debian GNU/Linux, il existe un standard shell appelé , mais je connais beaucoup de gens qui aiment utiliser .

Enfin, dans de très petites la situation, il existe un outil spécial appelé avec son propre shell interprète ().

Chaîne demandée

La chaîne de l'échantillon dans la question, c'est:

IN="bla@some.com;john@home.com"

Cela pourrait être utile avec des espaces et des espaces pourrait modifier le résultat de la routine, je préfère utiliser cet exemple de chaîne:

 IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"

Scinde une chaîne basée sur délimiteur dans (version >=4.2)

En vertu de pur bash, on peut utiliser des tableaux et des IFS:

var="bla@some.com;john@home.com;Full Name <fulnam@other.org>"

oIFS="$IFS"
IFS=";"
declare -a fields=($var)
IFS="$oIFS"
unset oIFS

IFS=\; read -a fields <<<"$var"

En utilisant cette syntaxe cadre de la récente bash ne pas changer l' $IFS pour la session en cours, mais uniquement pour la commande en cours:

set | grep ^IFS=
IFS=$' \t\n'

Maintenant, la chaîne var est découpé et stockées dans un tableau (nommé en fields):

set | grep ^fields=\\\|^var=
fields=([0]="bla@some.com" [1]="john@home.com" [2]="Full Name <fulnam@other.org>")
var='bla@some.com;john@home.com;Full Name <fulnam@other.org>'

C'est le quickiest façon de le faire car il n'y a pas de fourches et aucune ressource externe appelé.

À partir de là, vous pouvez utiliser la syntaxe que vous connaissez déjà pour le traitement de chaque domaine;

for x in "${fields[@]}";do
    echo "> [$x]"
    done
> [bla@some.com]
> [john@home.com]
> [Full Name <fulnam@other.org>]

ou une goutte de chaque champ après le traitement (j'aime ce décalage approche):

while [ "$fields" ] ;do
    echo "> [$fields]"
    fields=("${fields[@]:1}")
    done
> [bla@some.com]
> [john@home.com]
> [Full Name <fulnam@other.org>]

ou même pour une simple impression (plus courte syntaxe):

printf "> [%s]\n" "${fields[@]}"
> [bla@some.com]
> [john@home.com]
> [Full Name <fulnam@other.org>]

Scinde une chaîne basée sur délimiteur dans le

Mais si vous écrivez quelque chose d'utilisable dans de nombreuses coquilles, vous devez ne pas utiliser bashisms.

Il y a une syntaxe, utilisé dans de nombreuses coquilles, pour scinder une chaîne accros de la première ou de la dernière occurence d'une chaîne:

${var#*SubStr}  # will drop begin of string upto first occur of `SubStr`
${var##*SubStr} # will drop begin of string upto last occur of `SubStr`
${var%SubStr*}  # will drop part of string from last occur of `SubStr` to the end
${var%%SubStr*} # will drop part of string from first occur of `SubStr` to the end

( Le manque de c'est la principale raison de ma réponse à la publication ;)

Ce petit exemple de script fonctionne bien sous , , , et a été testé sous Mac-OS bash:

var="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
while [ "$var" ] ;do
    iter=${var%%;*}
    echo "> [$iter]"
    [ "$var" = "$iter" ] && \
        var='' || \
        var="${var#*;}"
  done
> [bla@some.com]
> [john@home.com]
> [Full Name <fulnam@other.org>]

Amusez-vous!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X