Напевно, найпростіший і найбезпечніший спосіб роботи в BASH 3 і вище:
var="string to split"
read -ra arr <<<"$var"
(де arr
масив, який приймає розділені частини рядка) або, якщо у вводі можуть бути нові рядки, і вам потрібно більше, ніж просто перший рядок:
var="string to split"
read -ra arr -d '' <<<"$var"
(зверніть увагу на пробіл -d ''
, який не можна залишити), але це може дати вам несподіваний новий рядок із<<<"$var"
(оскільки це неявно додає НЧ в кінці).
Приклад:
touch NOPE
var="* a *"
read -ra arr <<<"$var"
for a in "${arr[@]}"; do echo "[$a]"; done
Виводить очікуване
[*]
[a]
[*]
оскільки це рішення (на відміну від усіх попередніх рішень тут) не схильне до несподіваного та часто неконтрольованого поглинання оболонок.
Також це дає вам всю потужність IFS, як ви, мабуть, хочете:
Приклад:
IFS=: read -ra arr < <(grep "^$USER:" /etc/passwd)
for a in "${arr[@]}"; do echo "[$a]"; done
Виходить щось на кшталт:
[tino]
[x]
[1000]
[1000]
[Valentin Hilbig]
[/home/tino]
[/bin/bash]
Як бачите, простори можна зберегти і таким чином:
IFS=: read -ra arr <<<' split : this '
for a in "${arr[@]}"; do echo "[$a]"; done
виходи
[ split ]
[ this ]
Зауважте, що поводження з IFS
BASH є предметом самостійно, тому зробіть свої тести, деякі цікаві теми з цього приводу:
unset IFS
: Ігнорує запуски SPC, TAB, NL та на лінії починається та закінчується
IFS=''
: Немає розділення поля, просто все читає
IFS=' '
: Запуск SPC (і лише SPC)
Якийсь останній приклад
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
виходи
1 [this is]
2 [a test]
поки
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
виходи
1 [this]
2 [is]
3 [a]
4 [test]
До речі:
Якщо ви не звикли до цього $'ANSI-ESCAPED-STRING'
звикати, це час.
Якщо ви не включаєте -r
(як у read -a arr <<<"$var"
), тоді читання робить зворотну косу рису втечею. Це залишається як вправа для читача.
Для другого питання:
Щоб перевірити наявність чогось у рядку, я зазвичай дотримуюся case
, оскільки це може перевірити наявність декількох випадків одночасно (зауважте: case виконує лише першу відповідність, якщо вам потрібно пропустити використання case
заяв multiplce ), і ця потреба досить часто буває (каламбур) призначений):
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
Таким чином, ви можете встановити значення повернення для перевірки SPC таким чином:
case "$var" in (*' '*) true;; (*) false;; esac
Чому case
? Оскільки це, як правило, трохи читабельніше, ніж послідовності регулярних виразів, і завдяки метахарактерам Shell він дуже добре обробляє 99% усіх потреб.