Bash: Как токенизировать строковую переменную?
Заголовок: Как разбить строку на токены, используя пробелы в качестве разделителя?
Тело сообщения:
У меня есть переменная типа строка, значение которой — "john is 17 years old"
. Мне нужно разбить эту строку на токены, используя пробелы в качестве разделителя. Могу ли я использовать awk
для этой задачи, и если да, то как именно? Будет ли это наилучшим способом, или есть другие подходы? Спасибо заранее за помощь!
5 ответ(ов)
В вашем примере вы разделяете строку на токены с использованием пробелов и символа ;
в Bash. Давайте разберем это по шагам.
Деление строки на токены по пробелам
Для первой строки:
$ string="john is 17 years old"
$ tokens=( $string )
$ echo ${tokens[*]}
Здесь вы создаете строку с именем string
, содержащую текст "john is 17 years old". Затем вы используете массив tokens
для хранения токенов, полученных из строки. По умолчанию в Bash разделитель – это пробел, поэтому строка делится на токены по пробелам. Команда echo ${tokens[*]}
выведет все токены в одной строке, разделенные пробелами.
Деление строки на токены по другому разделителю, например, ;
Для разделения строки с использованием символа ;
:
$ string="john;is;17;years;old"
$ OLDIFS="$IFS"
$ IFS=';' tokens=( $string )
$ echo ${tokens[*]}
$ IFS="$OLDIFS" # restore IFS
Здесь вы сначала сохраняете текущее значение переменной IFS
(Internal Field Separator) в переменную OLDIFS
. Затем вы изменяете значение IFS
на ;
, что позволяет вам разбить строку string
на токены там, где находятся символы ;
.
После создания массива tokens
вы снова используете echo ${tokens[*]}
, чтобы вывести токены в одной строке. В конце вы восстанавливаете оригинальное значение IFS
, чтобы избежать нежелательных последствий в дальнейшем.
Таким образом, использование переменной IFS
позволяет гибко настраивать, как именно строка будет разбиваться на токены в Bash.
Для использования автоматической токенизации неочищенных переменных в оболочке вы можете сделать следующее:
$ string="john is 17 years old"
$ for word in $string; do echo "$word"; done
john
is
17
years
old
Если вы хотите изменить разделитель, можете установить переменную $IFS
, что обозначает "внутренний разделитель полей". Значение по умолчанию для $IFS
— это " \t\n"
(пробел, табуляция, новая строка).
$ string="john_is_17_years_old"
$ (IFS='_'; for word in $string; do echo "$word"; done)
john
is
17
years
old
Обратите внимание, что во втором примере я добавил круглые скобки вокруг второй строки. Это создает подсборку (sub-shell), чтобы изменение $IFS
не сохранялось. Обычно вы не хотите постоянно изменять $IFS
, так как это может вызвать проблемы с другими командами оболочки.
Вы можете использовать команду set
для разделения строки на отдельные элементы, а затем получить доступ к этим элементам через позиционные параметры. Вот пример, как это делается:
$ string="john is 17 years old"
$ set -- $string
$ echo $1
john
$ echo $2
is
$ echo $3
17
В этом примере переменная string
содержит строку "john is 17 years old". Команда set -- $string
разбивает строку на отдельные слова и задает их как позиционные параметры. После этого вы можете получить доступ к первому ($1
), второму ($2
) и третьему ($3
) словам с помощью команды echo
. Таким образом, $1
будет равен "john", $2
— "is", а $3
— "17". Обратите внимание, что остальные слова также будут доступны в последующих позиционных параметрах.
Вы можете попробовать что-то вроде этого:
#!/bin/bash
n=0
a=/home/file.txt
for i in `cat ${a} | tr ' ' '\n'` ; do
str=${str},${i}
let n=$n+1
var=`echo "var${n}"`
echo $var is ... ${i}
done
Этот скрипт читает файл file.txt
, разбивает его содержимое по пробелам и выводит каждое слово вместе с соответствующим номером переменной. Обратите внимание, что использование let
для инкрементации переменной n
не является обязательным; можно использовать простую арифметику: n=$((n + 1))
. Также желательно избегать использования обратных кавычек для команд и заменить их на $(...)
.
Пример улучшенной версии:
#!/bin/bash
n=0
a=/home/file.txt
str=""
while read -r i; do
str="${str},${i}"
n=$((n + 1))
var="var${n}"
echo "$var is ... $i"
done < <(tr ' ' '\n' < "$a")
Этот вариант более устойчив и читабелен.
Вы можете использовать расширенные регулярные выражения POSIX в sed
, чтобы разбить строку по несловесным символам, как в приведенном вами примере. Вот краткое объяснение кода:
str='a b c d'
echo "$str" | sed -E 's/\W+/\n/g' | hexdump -C
В этом коде переменная str
содержит строку с пробелами между словами. Команда echo
передает эту строку в sed
, который использует следующий шаблон:
s/\W+/\n/g
: это заменяет последовательности несловесных символов (включая пробелы, табуляции и другие символы, исключая символ подчеркивания_
) на символ новой строки (\n
).
Таким образом, sed
обрабатывает строку, создавая новую строку для каждого слова, и выводит результат в шестнадцатеричном формате с помощью hexdump
.
Обратите внимание, что \W
соответствует любому несловесному символу, включая пробелы, табуляции, символы возврата и специальные знаки, но исключает символ подчеркивания. Это означает, что snake_case
(например, my_variable
) будет считаться одним словом, в то время как kebab-case
(например, my-variable
) уже будет рассматриваться как два слова.
Также помните, что ведущие и заключительные пробелы создадут пустую строку в выводе. Это поведение будет аналогично функции re.split(r'\W+', str)
в Python, где строка также будет разбита на основе несловесных символов.
Как изменить цвет вывода echo в Linux
Как работает "cat << EOF" в bash?
Как использовать 'grep' для непрерывного потока?
Как создать файл в Linux из терминала? [закрыто]
Автоматический вход в Docker через Bash-скрипт