Bash
Разделение слов
Поиск…
Синтаксис
- Установите IFS в новую строку: IFS = $ '\ n'
- Установите IFS на nullstring: IFS =
- Установите IFS в / символ: IFS = /
параметры
параметр | подробности |
---|---|
IFS | Внутренний разделитель полей |
-Икс | Команды печати и их аргументы по мере их выполнения (опция Shell) |
замечания
- Разделение слов не выполняется во время присвоений, например
newvar=$var
- Разделение слов не выполняется в конструкции
[[ ... ]]
- Используйте двойные кавычки для переменных, чтобы предотвратить разделение слов
Разделение с IFS
Чтобы быть более понятным, давайте создадим скрипт с именем showarg
:
#!/usr/bin/env bash
printf "%d args:" $#
printf " <%s>" "$@"
echo
Теперь посмотрим различия:
$ var="This is an example"
$ showarg $var
4 args: <This> <is> <an> <example>
$var
делится на 4 аргумента.IFS
- это символы пробела и, следовательно, разбиение слов происходит в пробелах
$ var="This/is/an/example"
$ showarg $var
1 args: <This/is/an/example>
В предыдущем слове расщепление не произошло, потому что символы
IFS
не были найдены.
Теперь давайте установим IFS=/
$ IFS=/
$ var="This/is/an/example"
$ showarg $var
4 args: <This> <is> <an> <example>
$var
делится на 4 аргумента, а не один аргумент.
Что, когда и почему?
Когда оболочка выполняет расширение параметра , подмену команды , переменное или арифметическое расширение , он сканирует границы слова в результате. Если какая-либо граница слова найдена, результат разбивается на несколько слов в этой позиции. Граница слова определяется переменной оболочки IFS
(Internal Field Separator). Значением по умолчанию для IFS являются пробел, табуляция и новая строка, то есть разделение слов будет происходить на этих трех символах пробела, если это не будет предотвращено явно.
set -x
var='I am
a
multiline string'
fun() {
echo "-$1-"
echo "*$2*"
echo ".$3."
}
fun $var
В приведенном выше примере это то, как выполняется функция fun
:
fun I am a multiline string
$var
делится на 5 аргументов, будет напечатан толькоI
,am
иa
.
IFS & разбиение слов
Посмотрите, что, когда и почему, если вы не знаете о присоединении IFS к разбиению слов
давайте зададим IFS только символу пробела:
set -x
var='I am
a
multiline string'
IFS=' '
fun() {
echo "-$1-"
echo "*$2*"
echo ".$3."
}
fun $var
Это расщепление слова будет работать только на пространствах. Функция fun
будет выполнена следующим образом:
fun I 'am
a
multiline' string
$var
делится на 3 аргумента.I
,am\na\nmultiline
иstring
будет напечатана
Давайте установим IFS только для новой строки:
IFS=$'\n'
...
Теперь fun
будет выполнена как:
fun 'I am' a 'multiline string'
$var
делится на 3 аргумента.I am
,a
,multiline string
будет напечатана
Давайте посмотрим, что произойдет, если мы установим IFS в nullstring:
IFS=
...
На этот раз fun
будет выполнена следующим образом:
fun 'I am
a
multiline string'
$var
не разделяется, т. е. остается одним аргументом.
Вы можете предотвратить разбиение слов, установив IFS в nullstring
Общий способ предотвращения разделения слов - использовать двойную кавычку:
fun "$var"
будет предотвращать расщепление слов во всех рассмотренных выше случаях, т. е. функция fun
будет выполняться только с одним аргументом.
Плохие эффекты расщепления слов
$ a='I am a string with spaces'
$ [ $a = $a ] || echo "didn't match"
bash: [: too many arguments
didn't match
[ $a = $a ]
интерпретируется как[ I am a string with spaces = I am a string with spaces ]
.[
этоtest
команда, для которойI am a string with spaces
- это не один аргумент, а 6 аргументов!
$ [ $a = something ] || echo "didn't match"
bash: [: too many arguments
didn't match
[ $a = something ]
интерпретируется как[ I am a string with spaces = something ]
$ [ $(grep . file) = 'something' ]
bash: [: too many arguments
Команда
grep
возвращает многострочную строку с пробелами, поэтому вы можете просто представить, сколько аргументов существует ...: D
Посмотрите, что, когда и зачем основы.
Полезность расщепления слов
Существуют случаи, когда разбиение слов может быть полезным:
Заполнение массива:
arr=($(grep -o '[0-9]\+' file))
Это заполнит
arr
всеми численными значениями, найденными в файле
Циклическое выделение пробелов:
words='foo bar baz'
for w in $words;do
echo "W: $w"
done
Выход:
W: foo
W: bar
W: baz
Передача разделенных пробелов параметров, которые не содержат пробелов:
packs='apache2 php php-mbstring php-mysql'
sudo apt-get install $packs
или же
packs='
apache2
php
php-mbstring
php-mysql
'
sudo apt-get install $packs
Это установит пакеты. Если вы удвоите кавычки
$packs
то это вызовет ошибку.
Unquoetd
$packs
отправляет все имена разделяемых пространств в качестве аргументовapt-get
, в то время как цитирование будет отправлять строку$packs
как один аргумент, а затемapt-get
попытается установить пакет с именемapache2 php php-mbstring php-mysql
(для первого), который, очевидно, не существует
Посмотрите, что, когда и зачем основы.
Разделение по разделительным изменениям
Мы можем просто выполнить простую замену разделителей из пространства на новую, как показано ниже.
echo $sentence | tr " " "\n"
Он разделит значение sentence
переменной и покажет его по строке соответственно.