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