Il modo probabilmente più semplice e sicuro in BASH 3 e versioni successive è:
var="string to split"
read -ra arr <<<"$var"
(dove si arr
trova l'array che accetta le parti divise della stringa) o, se potrebbero esserci newline nell'input e si desidera più della semplice prima riga:
var="string to split"
read -ra arr -d '' <<<"$var"
(si prega di notare lo spazio in -d ''
, non può essere lasciato da parte), ma questo potrebbe darvi un inaspettato newline da <<<"$var"
(poiché ciò aggiunge implicitamente un LF alla fine).
Esempio:
touch NOPE
var="* a *"
read -ra arr <<<"$var"
for a in "${arr[@]}"; do echo "[$a]"; done
Emette il previsto
[*]
[a]
[*]
poiché questa soluzione (contrariamente a tutte le soluzioni precedenti qui) non è soggetta a globbing inaspettato e spesso incontrollabile delle coperture.
Anche questo ti dà tutta la potenza di IFS come probabilmente desideri:
Esempio:
IFS=: read -ra arr < <(grep "^$USER:" /etc/passwd)
for a in "${arr[@]}"; do echo "[$a]"; done
Emette qualcosa del tipo:
[tino]
[x]
[1000]
[1000]
[Valentin Hilbig]
[/home/tino]
[/bin/bash]
Come puoi vedere, anche gli spazi possono essere preservati in questo modo:
IFS=: read -ra arr <<<' split : this '
for a in "${arr[@]}"; do echo "[$a]"; done
uscite
[ split ]
[ this ]
Si noti che la gestione di IFS
in BASH è un argomento a sé stante, quindi fare i test, alcuni argomenti interessanti su questo:
unset IFS
: Ignora le serie di SPC, TAB, NL e l'inizio e la fine della linea
IFS=''
: Nessuna separazione dei campi, legge solo tutto
IFS=' '
: Esecuzioni di SPC (e solo SPC)
Qualche ultimo esempio
var=$'\n\nthis is\n\n\na test\n\n'
IFS=$'\n' read -ra arr -d '' <<<"$var"
i=0; for a in "${arr[@]}"; do let i++; echo "$i [$a]"; done
uscite
1 [this is]
2 [a test]
mentre
unset IFS
var=$'\n\nthis is\n\n\na test\n\n'
read -ra arr -d '' <<<"$var"
i=0; for a in "${arr[@]}"; do let i++; echo "$i [$a]"; done
uscite
1 [this]
2 [is]
3 [a]
4 [test]
BTW:
Se non sei abituato ad $'ANSI-ESCAPED-STRING'
abituarti, è un risparmio di tempo.
Se non includi -r
(come in read -a arr <<<"$var"
), allora leggi fa backslash escape. Questo è lasciato come esercizio per il lettore.
Per la seconda domanda:
Per testare qualcosa in una stringa di solito mi attengo case
, poiché questo può controllare più casi contemporaneamente (nota: case esegue solo la prima corrispondenza, se hai bisogno di fallthrough usa case
istruzioni multiplce ), e questa necessità è abbastanza spesso il caso (gioco di parole destinato):
case "$var" in
'') empty_var;; # variable is empty
*' '*) have_space "$var";; # have SPC
*[[:space:]]*) have_whitespace "$var";; # have whitespaces like TAB
*[^-+.,A-Za-z0-9]*) have_nonalnum "$var";; # non-alphanum-chars found
*[-+.,]*) have_punctuation "$var";; # some punctuation chars found
*) default_case "$var";; # if all above does not match
esac
Quindi puoi impostare il valore di ritorno per verificare SPC in questo modo:
case "$var" in (*' '*) true;; (*) false;; esac
Perché case
? Perché di solito è un po 'più leggibile delle sequenze regex e grazie ai metacaratteri Shell gestisce molto bene il 99% di tutte le esigenze.