Le shell tipo Bourne / POSIX hanno un operatore split + glob ed è invocato ogni volta che si lascia un parametro di espansione ( $var
, $-
...), sostituzione comando ( $(...)
) o espansione aritmetica ( $((...))
) non quotato nel contesto dell'elenco.
In realtà, l'hai invocato per errore quando lo hai fatto for name in ${array[@]}
invece di for name in "${array[@]}"
. (In realtà, dovresti stare attento che invocare quell'operatore in quel modo per errore è fonte di molti bug e vulnerabilità di sicurezza ).
Quell'operatore è configurato con il $IFS
parametro speciale (per dire su quali personaggi dividere (anche se attenzione che spazio, tab e newline ricevono un trattamento speciale lì)) e l' -f
opzione per disabilitare ( set -f
) o abilitare ( set +f
) la glob
parte.
Si noti inoltre che mentre S
in $IFS
era originariamente (nella shell Bourne da dove $IFS
proviene) per Separatore, nelle shell POSIX, i caratteri in $IFS
dovrebbero piuttosto essere visti come delimitatori o terminatori (vedere sotto per un esempio).
Quindi dividere su _
:
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.
Per vedere la distinzione tra separatore e delimitatore , prova su:
string='var1_var2_'
Ciò lo dividerà in var1
e var2
solo (nessun elemento extra vuoto).
Quindi, per renderlo simile a JavaScript split()
, avresti bisogno di un ulteriore passaggio:
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
(nota che dividerebbe un elemento vuoto $string
in 1 (non 0 ), come JavaScript split()
.
Per vedere la scheda trattamenti speciali, spazio e newline ricevere, confronta:
IFS=' '; string=' var1 var2 '
(dove arrivi var1
e var2
) con
IFS='_'; string='_var1__var2__'
dove si ottiene: ''
, var1
, ''
, var2
, ''
.
Si noti che la zsh
shell non invoca quell'operatore split + glob in modo implicito a meno che non sia presente sh
o ksh
emulato. Lì, devi invocarlo esplicitamente. $=string
per la parte divisa, $~string
per la parte glob ( $=~string
per entrambi) e ha anche un operatore di divisione in cui è possibile specificare il separatore:
array=(${(s:_:)string})
o per preservare gli elementi vuoti:
array=("${(@s:_:)string}")
Si noti che non s
è per scissione , non delimitando (anche con $IFS
una nota POSIX non conformità di zsh
). È diverso da quello di JavaScript split()
in quanto una stringa vuota è suddivisa in elemento 0 (non 1).
Una notevole differenza con $IFS
-splitting è che si ${(s:abc:)string}
divide sulla abc
stringa, mentre con IFS=abc
, che si divide su a
, b
o c
.
Con zsh
e ksh93
, il trattamento speciale che spazio, tab o newline riceve può essere rimosso raddoppiandolo $IFS
.
Come nota storica, la shell Bourne (l'antenato o le moderne shell POSIX) ha sempre messo a nudo gli elementi vuoti. Aveva anche una serie di bug relativi alla divisione e all'espansione di $ @ con valori non predefiniti di $IFS
. Ad esempio IFS=_; set -f; set -- $@
non sarebbe equivalente a IFS=_; set -f; set -- $1 $2 $3...
.
Frazionamento su regexps
Ora per qualcosa di più vicino a JavaScript split()
che può dividere su espressioni regolari, dovresti fare affidamento su utility esterne.
Nel toolbox POSIX, awk
ha un split
operatore che può dividere su espressioni regolari estese (che sono più o meno un sottoinsieme delle espressioni regolari simili al Perl supportate da 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" '[_+]+'))"
La zsh
shell ha il supporto incorporato per le espressioni regolari compatibili con Perl (nel suo zsh/pcre
modulo), ma usarlo per dividere una stringa, sebbene possibile sia relativamente ingombrante.
shell
stai usando, conbash
te puoi fareIFS='_' read -a array <<< "${string}"