Prawdopodobnie najłatwiejszym i najbezpieczniejszym sposobem w BASH 3 i nowszych jest:
var="string to split"
read -ra arr <<<"$var"
(gdzie arr
jest tablica, która pobiera podzielone części łańcucha) lub, jeśli na wejściu mogą znajdować się znaki nowej linii i potrzebujesz więcej niż tylko pierwszego wiersza:
var="string to split"
read -ra arr -d '' <<<"$var"
(zwróć uwagę na miejsce w środku -d ''
, nie można go zostawić), ale może to dać nieoczekiwany znak nowej linii <<<"$var"
(ponieważ domyślnie dodaje to LF na końcu).
Przykład:
touch NOPE
var="* a *"
read -ra arr <<<"$var"
for a in "${arr[@]}"; do echo "[$a]"; done
Wyprowadza oczekiwane
[*]
[a]
[*]
ponieważ to rozwiązanie (w przeciwieństwie do wszystkich poprzednich rozwiązań tutaj) nie jest podatne na nieoczekiwane i często niekontrolowane globowanie powłoki.
Daje to również pełną moc IFS, jak zapewne chcesz:
Przykład:
IFS=: read -ra arr < <(grep "^$USER:" /etc/passwd)
for a in "${arr[@]}"; do echo "[$a]"; done
Wyprowadza coś takiego:
[tino]
[x]
[1000]
[1000]
[Valentin Hilbig]
[/home/tino]
[/bin/bash]
Jak widać, spacje można również zachować w ten sposób:
IFS=: read -ra arr <<<' split : this '
for a in "${arr[@]}"; do echo "[$a]"; done
wyjścia
[ split ]
[ this ]
Należy pamiętać, że obsługa IFS
w BASH jest przedmiotem sama w sobie, podobnie jak testy, kilka interesujących tematów na ten temat:
unset IFS
: Ignoruje przebiegi SPC, TAB, NL oraz on-line start i end
IFS=''
: Bez separacji pola, wszystko czyta
IFS=' '
: Uruchamia SPC (i tylko SPC)
Ostatni przykład
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
wyjścia
1 [this is]
2 [a test]
podczas
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
wyjścia
1 [this]
2 [is]
3 [a]
4 [test]
BTW:
Jeśli nie jesteś $'ANSI-ESCAPED-STRING'
przyzwyczajony do tego, oznacza to oszczędność czasu.
Jeśli nie podasz -r
(jak w read -a arr <<<"$var"
), wtedy read unika odwrotnego ukośnika. Pozostaje to jako ćwiczenie dla czytelnika.
W przypadku drugiego pytania:
Aby przetestować coś w ciągu, zwykle trzymam się tego case
, ponieważ może to sprawdzić wiele przypadków jednocześnie (uwaga: case wykonuje tylko pierwsze dopasowanie, jeśli potrzebujesz przewrotnego użycia case
instrukcji mnożenia ), a taka potrzeba jest dość często (pun zamierzony):
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
Możesz więc ustawić wartość zwracaną w celu sprawdzenia SPC w następujący sposób:
case "$var" in (*' '*) true;; (*) false;; esac
Dlaczego case
? Ponieważ zwykle jest nieco bardziej czytelny niż sekwencje wyrażeń regularnych, a dzięki metaznakom Shell bardzo dobrze radzi sobie z 99% wszystkich potrzeb.