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 $IFS
paramè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' -f
option pour désactiver ( set -f
) ou activer ( set +f
) la glob
partie.
Notez également que si S
in $IFS
était à l'origine (dans le shell Bourne d'où $IFS
vient) pour Separator, dans les shells POSIX, les caractères dans $IFS
devraient 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 var1
et var2
seulement (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 $string
en 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 var1
et var2
) avec
IFS='_'; string='_var1__var2__'
où vous obtenez: ''
, var1
, ''
, var2
, ''
.
Notez que le zsh
shell n'invoque pas cet opérateur split + glob implicitement comme ça sauf dans sh
ou en ksh
émulation. Là, vous devez l'invoquer explicitement. $=string
pour la partie scindée, $~string
pour la partie glob ( $=~string
pour 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 s
pour 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 abc
chaîne, tandis qu'avec IFS=abc
, cela se diviserait sur a
, b
ou c
.
Avec zsh
et 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, awk
possède un split
opé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 zsh
shell a un support intégré pour les expressions régulières compatibles Perl (dans son zsh/pcre
module), mais l'utiliser pour diviser une chaîne, bien que possible, est relativement lourd.
shell
- ce que vous utilisez, avecbash
vous pouvez faireIFS='_' read -a array <<< "${string}"