У меня есть строка, содержащая много слов, по крайней мере, один пробел между каждыми двумя. Как я могу разбить строку на отдельные слова, чтобы я мог проходить через них?
Строка передается в качестве аргумента. Например ${2} == "cat cat file"
. Как я могу пройти через это?
Кроме того, как я могу проверить, содержит ли строка пробелы?
Ответы:
Вы пытались просто передать строковую переменную в
for
цикл? Bash, например, будет автоматически разделяться на пустые места.источник
A=${A}${word})
.touch NOPE; var='* a *'; for a in $var; do echo "[$a]"; done
выходные данные[NOPE] [a] [NOPE]
вместо ожидаемых[*] [a] [*]
(LFs заменены на SPC для удобства чтения).Мне нравится преобразование в массив, чтобы иметь возможность доступа к отдельным элементам:
теперь вы можете получить доступ к отдельным элементам напрямую (начинается с 0):
или преобразовать обратно в строку для цикла:
Конечно, раньше было получено ответное сообщение о том, что цикл проходил напрямую, но недостатком этого ответа было то, что он не отслеживал отдельные элементы для последующего использования:
Смотрите также Bash Array Reference .
источник
touch NOPE; var='* a *'; arr=($var); set | grep ^arr=
результатыarr=([0]="NOPE" [1]="a" [2]="NOPE")
вместо ожидаемыхarr=([0]="*" [1]="a" [2]="*")
Просто используйте встроенные оболочки "set". Например,
После этого отдельные слова в $ text будут в $ 1, $ 2, $ 3 и т. Д. Для устойчивости обычно делают
обработать случай, когда $ text пуст или начать с тире. Например:
Это печатает
источник
awk
ноset
гораздо проще. Теперь яset
фанат. Спасибо @ Идеально!touch NOPE; var='* a *'; set -- $var; for a; do echo "[$a]"; done
вывод[NOPE] [a] [NOPE]
вместо ожидаемого[*] [a] [*]
. Используйте его, только если вы на 101% уверены, что в разделенной строке метасимволы SHELL отсутствуют!set -f
доset -- $var
иset +f
после отключить сглаживание.set -f
твоим решением тоже безопасно. Ноset +f
это значение по умолчанию для каждой оболочки, поэтому это важная деталь, на которую следует обратить внимание, потому что другие, вероятно, не знают об этом (как я тоже).Вероятно, наиболее простой и безопасный способ в BASH 3 и выше:
(где
arr
массив, который принимает разделенные части строки) или, если во вводе могут быть символы новой строки, и вам нужно больше, чем просто первая строка:(обратите внимание на пробел
-d ''
, он не может быть пропущен), но это может дать вам неожиданный символ новой строки от<<<"$var"
(поскольку это неявно добавляет LF в конце).Пример:
Выходит ожидаемый
так как это решение (в отличие от всех предыдущих решений здесь) не подвержено неожиданному и часто неконтролируемому выкалыванию оболочки.
Также это дает вам всю мощь IFS, как вы, вероятно, хотите:
Пример:
Выводит что-то вроде:
Как видите, пробелы можно сохранить и таким образом:
выходы
Обратите внимание, что обработка
IFS
в BASH сама по себе является предметом, поэтому проведите тесты, некоторые интересные темы на эту тему:unset IFS
: Игнорирует прогоны SPC, TAB, NL и начинается и заканчивается на линииIFS=''
: Без разделения полей, просто все читаетIFS=' '
: Запускает SPC (и только SPC)Последний пример
выходы
пока
выходы
КСТАТИ:
Если вы не привыкли к
$'ANSI-ESCAPED-STRING'
этому, это экономит время.Если вы не включаете
-r
(как вread -a arr <<<"$var"
), тогда read выполняет обратную косую черту. Это оставлено как упражнение для читателя.По второму вопросу:
Чтобы проверить что-то в строке, я обычно придерживаюсь
case
, так как это может проверять сразу несколько случаев (примечание: case выполняет только первое совпадение, если вам нужно упасть, используйтеcase
операторы multiplce ), и это часто случается (pun предназначена):Таким образом, вы можете установить возвращаемое значение для проверки SPC следующим образом:
Почему
case
? Поскольку он обычно более читабелен, чем последовательности регулярных выражений, и благодаря метасимволам Shell он хорошо обрабатывает 99% всех потребностей.источник
set -f
илиset -o noglob
для переключения глобализации, чтобы метасимволы оболочки больше не наносили вреда в этом контексте. Но я на самом деле не дружу с этим, так как это оставляет много возможностей оболочки / очень подвержено ошибкам при переключении назад и вперед в этом параметре.;&
добиться этого. Не совсем уверен, в какой версии bash это появилось. Я пользователь 4.3;&
это принудительное падение без проверки шаблона, как в C. И есть также то,;;&
что просто продолжает делать дальнейшие проверки шаблона. Так;;
это какif ..; then ..; else if ..
и;;&
какif ..; then ..; fi; if ..
, где;&
это похожеm=false; if ..; then ..; m=:; fi; if $m || ..; then ..
- никто не перестает учиться (у других););;&
прежде чем вы прокомментировали: D Спасибо, и пусть снаряд будет с вами;)Для проверки пробелов используйте grep:
источник
echo "X" |
обычно может быть заменен<<<"X"
, например:grep -s " " <<<"This contains SPC"
. Вы можете заметить разницу, если вы делаете что-то вродеecho X | read var
в отличие отread var <<< X
. Только последняя импортирует переменнуюvar
в текущую оболочку, а для доступа к ней в первом варианте необходимо сгруппировать ее так:echo X | { read var; handle "$var"; }
(A) Чтобы разделить предложение на слова (разделенные пробелами), вы можете просто использовать IFS по умолчанию, используя
Пример выполнения следующего фрагмента
будет выводить
Как вы можете видеть, вы можете использовать одинарные или двойные кавычки тоже без проблем.
Примечания:
- это в основном то же самое, что и ответ моба , но таким образом вы сохраняете массив для любых дальнейших нужд. Если вам нужен только один цикл, вы можете использовать его ответ, который на одну строку короче :)
- пожалуйста, обратитесь к этому вопросу для поиска альтернативных методов разделения строки на основе разделителя.
(B) Чтобы проверить наличие символа в строке, вы также можете использовать совпадение регулярного выражения.
Пример для проверки наличия пробела вы можете использовать:
источник
Для проверки пробелов только с помощью bash:
источник
Это выводит каждое слово, вы можете обработать этот список так, как считаете нужным.
источник