Разделить 1 аргумент на 2 аргумента, используя regexp в bash script
Вот моя ситуация. В настоящее время у меня есть script, который принимает два аргумента: имя книги и название главы. Например:
$ myscript book1 chap1
Теперь, по причинам, которые потребуются долгое время, я бы предпочел, чтобы мой script мог принять один аргумент следующего формата: {book name}. {chapter name}. Например:
$ myscript book1.chap1
Трудность для меня в том, что я не знаю, как взять строку $1 = abc.xyz и превратить ее в две отдельные переменные: $var1 = abc и $var2 = xyz. Как я могу это сделать?
Ответы
Ответ 1
Если это всего лишь два тега, вы можете использовать выражение bash
arg=$1
beforedot=${arg%.*}
afterdot=${arg#*.}
Это быстрее, чем cut
, потому что это оболочка встроена. Обратите внимание, что это ставит все перед первым последней точкой в beforedot
и все после afterdot
.
ИЗМЕНИТЬ
Также существует конструкция подстановки/переинтерпретации, если вы хотите разбить на произвольное число токенов:
string=a.b.c.d.e
tokens=(${string//\./ })
Вы заменяете точки пробелами, а затем интерпретируются как определение объявления массива + из-за круглых скобок вокруг него.
Однако я обнаружил, что это менее переносимо для siblings и потомков bash. Например, он не работает в моей любимой оболочке, zsh
.
Массивы должны быть разыменованы скобками и индексированы из 0:
echo "Third token: ${tokens[2]}"
Вы также можете прокручивать их, разыменовывая весь массив с помощью [@]:
for i in ${tokens[@]}
do
# do stuff
done
Ответ 2
Для полноты и после того, как вы спросили о методе regex:
pattern='^([^.]*)\.(.*)'
[[ $1 =~ $pattern ]]
book=${BASH_REMATCH[1]}
chapter=${BASH_REMATCH[2]}
Группы захвата являются элементами массива BASH_REMATCH
. Элемент 0 содержит полное совпадение.
Это регулярное выражение будет захватывать до первой точки в первом элементе. Все, что после первой точки, включая последовательные точки, будет во втором элементе. Регулярное выражение может быть легко изменено, чтобы разбить последнюю точку, если это необходимо.
Ответ 3
Если $arg
содержит book.chap
read BOOK CHAP<<<$(IFS="."; echo $arg)
задает переменные BOOK и CHAP соответственно. В нем используется внутренний разделитель полей bash (IFS), который определяет, как bash понимает границы слов. Если (скажем) у вас есть несколько разделителей в исходном $arg
, то просто укажите дополнительные переменные, чтобы содержать результаты.
Из здесь:
$IFS по умолчанию имеет пробелы (пробел, табуляцию и новую строку), но может быть например, для анализа файла данных с разделителями-запятыми
Ответ 4
Вы можете использовать круглые скобки для захвата двух частей; впоследствии вы можете использовать обратные ссылки, чтобы снова захватить их. Синтаксис отличается между языками; проверьте http://www.regular-expressions.info/brackets.html для урока по обратным ссылкам вообще.
Ответ 5
#!/bin/bash
book=${1%.*}
chapter=${1#*.}
printf 'book: %s\nchapter: %s\n' "$book" "$chapter"
Ответ 6
Активация шаблона с расширением параметра оболочки
Существует множество способов сделать то, что вы пытаетесь сделать. Один из способов, не описанных в других ответах, - замена шаблона.
Если вы знаете, что значение всегда будет правильно разделяться на период, вы можете применить подстановку шаблонов к значению, чтобы было легко подделать IFS. Например:
set -- foo.bar
myvar="${1/./ }"
echo $myvar
Это даст foo bar
.