Les shells de type Bourne / POSIX ont un opérateur split + glob et il est invoqué chaque fois que vous laissez une expansion de paramètre ( $var, $-...), une substitution de commande ( $(...)) ou une expansion arithmétique ( $((...))) sans guillemets dans le contexte d'une liste.
En fait, vous l'avez invoqué par erreur lorsque vous l'avez fait à la for name in ${array[@]}place de for name in "${array[@]}". (En fait, vous devez être conscient que l' invocation de cet opérateur par erreur est source de nombreux bugs et failles de sécurité ).
Cet opérateur est configuré avec le $IFSparamètre spécial (pour indiquer sur quels caractères se diviser (mais attention à ce que l'espace, la tabulation et la nouvelle ligne y reçoivent un traitement spécial)) et l' -foption pour désactiver ( set -f) ou activer ( set +f) la globpartie.
Notez également que si Sin $IFSétait à l'origine (dans le shell Bourne d'où $IFSvient) pour Separator, dans les shells POSIX, les caractères dans $IFSdevraient plutôt être considérés comme des délimiteurs ou des terminateurs (voir ci-dessous pour un exemple).
Donc, pour partager _:
string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
array=($string) # invoke the split+glob operator
for i in "${array[@]}"; do # loop over the array elements.
Pour voir la distinction entre séparateur et délimiteur , essayez:
string='var1_var2_'
Cela le divisera en var1et var2seulement (pas d'élément vide supplémentaire).
Donc, pour le rendre similaire à JavaScript split(), vous auriez besoin d'une étape supplémentaire:
string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
temp=${string}_ # add an extra delimiter
array=($temp) # invoke the split+glob operator
(notez qu'il diviserait un élément vide $stringen 1 (et non 0 ), comme JavaScript split()).
Pour voir l'onglet des traitements spéciaux, l'espace et la nouvelle ligne reçoivent, comparez:
IFS=' '; string=' var1 var2 '
(où vous obtenez var1et var2) avec
IFS='_'; string='_var1__var2__'
où vous obtenez: '', var1, '', var2, ''.
Notez que le zshshell n'invoque pas cet opérateur split + glob implicitement comme ça sauf dans shou en kshémulation. Là, vous devez l'invoquer explicitement. $=stringpour la partie scindée, $~stringpour la partie glob ( $=~stringpour les deux), et il a également un opérateur de scission où vous pouvez spécifier le séparateur:
array=(${(s:_:)string})
ou pour conserver les éléments vides:
array=("${(@s:_:)string}")
Notez qu'il existe spour le fractionnement , pas la délimitation (également avec $IFS, une non-conformité POSIX connue de zsh). Il est différent de JavaScript split()en ce sens qu'une chaîne vide est divisée en élément 0 (et non 1).
Une différence notable avec $IFS-splitting est que ${(s:abc:)string}se divise sur la abcchaîne, tandis qu'avec IFS=abc, cela se diviserait sur a, bou c.
Avec zshet ksh93, le traitement spécial que l'espace, la tabulation ou la nouvelle ligne reçoit peut être supprimé en les doublant $IFS.
Comme note historique, le shell Bourne (l'ancêtre ou les shell POSIX modernes) a toujours dépouillé les éléments vides. Il avait également un certain nombre de bogues liés au fractionnement et à l'expansion de $ @ avec des valeurs non par défaut de $IFS. Par exemple IFS=_; set -f; set -- $@, ne serait pas équivalent à IFS=_; set -f; set -- $1 $2 $3....
Fractionnement sur regexps
Maintenant, pour quelque chose de plus proche de JavaScript split()qui peut se diviser en expressions régulières, vous devez vous fier à des utilitaires externes.
Dans la boîte à outils POSIX, awkpossède un splitopérateur qui peut se diviser en expressions régulières étendues (ce sont plus ou moins un sous-ensemble des expressions régulières de type Perl prises en charge par JavaScript).
split() {
awk -v q="'" '
function quote(s) {
gsub(q, q "\\" q q, s)
return q s q
}
BEGIN {
n = split(ARGV[1], a, ARGV[2])
for (i = 1; i <= n; i++) printf " %s", quote(a[i])
exit
}' "$@"
}
string=a__b_+c
eval "array=($(split "$string" '[_+]+'))"
Le zshshell a un support intégré pour les expressions régulières compatibles Perl (dans son zsh/pcremodule), mais l'utiliser pour diviser une chaîne, bien que possible, est relativement lourd.
shell- ce que vous utilisez, avecbashvous pouvez faireIFS='_' read -a array <<< "${string}"