Вероятно, наиболее простой и безопасный способ в BASH 3 и выше:
var="string to split"
read -ra arr <<<"$var"
(где arr
массив, который принимает разделенные части строки) или, если во вводе могут быть символы новой строки, и вам нужно больше, чем просто первая строка:
var="string to split"
read -ra arr -d '' <<<"$var"
(обратите внимание на пробел -d ''
, он не может быть пропущен), но это может дать вам неожиданный символ новой строки от <<<"$var"
(поскольку это неявно добавляет LF в конце).
Пример:
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"
), тогда read выполняет обратную косую черту. Это оставлено как упражнение для читателя.
По второму вопросу:
Чтобы проверить что-то в строке, я обычно придерживаюсь case
, так как это может проверять сразу несколько случаев (примечание: case выполняет только первое совпадение, если вам нужно упасть, используйте case
операторы multiplce ), и это часто случается (pun предназначена):
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% всех потребностей.