Подтвердить что ты не робот

Разделить 1 аргумент на 2 аргумента, используя regexp в bash script

Вот моя ситуация. В настоящее время у меня есть script, который принимает два аргумента: имя книги и название главы. Например:

$ myscript book1 chap1

Теперь, по причинам, которые потребуются долгое время, я бы предпочел, чтобы мой script мог принять один аргумент следующего формата: {book name}. {chapter name}. Например:

$ myscript book1.chap1

Трудность для меня в том, что я не знаю, как взять строку $1 = abc.xyz и превратить ее в две отдельные переменные: $var1 = abc и $var2 = xyz. Как я могу это сделать?

4b9b3361

Ответ 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.