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 $IFSparametro speciale (per dire su quali personaggi dividere (anche se attenzione che spazio, tab e newline ricevono un trattamento speciale lì)) e l' -fopzione per disabilitare ( set -f) o abilitare ( set +f) la globparte.
Si noti inoltre che mentre Sin $IFSera originariamente (nella shell Bourne da dove $IFSproviene) per Separatore, nelle shell POSIX, i caratteri in $IFSdovrebbero 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 var1e var2solo (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 $stringin 1 (non 0 ), come JavaScript split().
Per vedere la scheda trattamenti speciali, spazio e newline ricevere, confronta:
IFS=' '; string=' var1 var2 '
(dove arrivi var1e var2) con
IFS='_'; string='_var1__var2__'
dove si ottiene: '', var1, '', var2, ''.
Si noti che la zshshell non invoca quell'operatore split + glob in modo implicito a meno che non sia presente sho kshemulato. Lì, devi invocarlo esplicitamente. $=stringper la parte divisa, $~stringper la parte glob ( $=~stringper 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 $IFSuna 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 abcstringa, mentre con IFS=abc, che si divide su a, bo c.
Con zshe 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, awkha un splitoperatore 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 zshshell ha il supporto incorporato per le espressioni regolari compatibili con Perl (nel suo zsh/pcremodulo), ma usarlo per dividere una stringa, sebbene possibile sia relativamente ingombrante.
shellstai usando, conbashte puoi fareIFS='_' read -a array <<< "${string}"