У меня есть строка, содержащаяся в переменной, и я хочу извлечь подстроки, основанные на позиции относительно другой подстроки. Мое решение, похоже, работает, если строка не отправляется в функцию как arg. Я использую оболочку bash.
#!/usr/bin/bash var0="-a check one two three" var1="check" function getsubstr() { echo ${*#*"${2}"} } # this prints 'one two three' which is what I want echo ${var0#*"${var1}"} # this prints '-a one two three', not what I want. getsubstr $var0
обратите внимание, что, когда я помещаю echo $*
в функцию getsubstr
он печатает ту же строку, что и $var0
(-> '-a check one two three'), и когда я помещаю echo $2
в функцию getsubstr
печатает ту же строку, что и $var1
(-> 'check'). Итак, мне кажется, что я прошу напечатать одну и ту же подстроку в обоих обстоятельствах.
Еще одна загадка заключается в том, что если вместо функции echo ${*#*"${2}"}
в функции getsubstr
я использую echo ${*%"${2}"*}
, я получаю тот же результат.
Любая помощь в понимании этого поведения была бы весьма признательна.
Кстати, я понимаю, что ${*:3}
внутри функции getsubstr
работает, чтобы вернуть подстроку, которую я хочу, но я пытаюсь понять поведение #*<regexp>
и %<regextp>*
.
Ваш getsubstr $var0
передает 5 аргументов функции
Кроме того, $ * и $ @ тестируют каждый отдельный $ 1 $ 2 и т. Д. Arg против # patttern
Что касается RegEx в bash
: я добавил несколько примеров в конце) .. и btw, '*' – это только специальный символ регулярного выражения, когда он используется в контексте регулярного выражения, т. Е. при использовании = ~ …
При первом использовании * в ${*
, специальное использование asterisk является именем (psuedo) var, которое расширяется до конкатенации всех vars: $ 1 $ 2 $ … и т. Д.
Второе использование звездочки в #*"${2}"
означает «$ 2», которому предшествует ничего, не содержащее ничего , должно быть сопоставлено с каждым переданным аргументом $ 1 и т. Д. Отдельно.
Следующий сценарий может помочь с $ @ и $ * (на примере) …
#!/bin/bash # getsubstr() { echo -n " ${#@} args"; [[ "$1$2$3$4$5$6" == *\ * ]] && echo " (with embedded spaces)" || echo " (no spaces)" echo ' "${*}" '\|"${*}"\| echo ' ${*} '\|${*}\| echo ' "${@}" '\|"${@}"\| echo ' ${@} '\|${@}\| echo ' "${*#*"${2}}" '\|"${*#*"${2}"}"\| echo ' ${*#*"${2}} '\|${*#*"${2}"}\| echo ' "${@#*"${2}}" '\|"${@#*"${2}"}"\| echo ' ${@#*"${2}} '\|${@#*"${2}"}\| echo ' ${*#B} '\|${*#B}\| echo ' "${*#B}" '\|"${*#B}"\| echo ' ${@#B} '\|${@#B}\| echo ' "${@#B}" '\|"${@#B}"\| } var0="a B c " echo echo -n "Passing "; getsubstr "$var0" ; echo echo -n "Passing "; getsubstr $var0 ; echo echo -n "Passing "; getsubstr "$var0" "$var0" ; echo echo -n "Passing "; getsubstr $var0 $var0 ; echo echo exit ###################################################################
RegEx в bash
# Regex checks: "=~" uses extended regular expression #+ Parenthesized subexpressions within the regular expression are saved #+ in the array variable BASH_REMATCH #+ $BASH_REMATCH / ${BASH_REMATCH[0]} is the string matching the entire regular expression. #+ ${BASH_REMATCH[n]} is the sub string matching the nth parenthesized subexpression [[ "abcdef" =~ (.)(.)(.) ]] && echo "# $BASH_REMATCH" # abc [[ "abcdef" =~ (.)(.)(.) ]] && echo "# ${BASH_REMATCH[0]}" # abc [[ "abcdef" =~ (.)(.)(.) ]] && echo "# ${BASH_REMATCH[2]}" # b [[ "abcdef" =~ (.)(.)(.) ]] && echo "# ${BASH_REMATCH[@]}" # abc abc
Причина, по которой вы видите этот тип поведения, состоит в том, что $*
или даже $@
расширяются до всех позиционных параметров: $1
, $2
и т. Д. Когда вы пытаетесь сделать расширение параметра (PE) на одном из этих двух специальных vars, вы применяют PE к каждому параметру позиции, а не к одной строке.
man bash
$ {параметр # слово}
Удалите соответствующий шаблон префикса. Слово расширяется для создания шаблона так же, как при расширении пути. Если шаблон совпадает с началом значения параметра, то результатом расширения является расширенное значение параметра с кратчайшим шаблоном соответствия (#'' case) or the longest matching pattern (the
случай ##'), удаленный , Если параметр равен @ или *, операция удаления паттерна применяется поочередно по каждому позиционному параметру, а расширение – это результирующий список.
По существу, вы делаете это:
getsubstr() { tmp=$2 for arg; do printf "%s " ${1#*$tmp} shift done }
Следующая функция работает, устанавливая $*
в temp var $tmp
потому что вы теперь применяете PE к обычной переменной один раз.
getsubstr() { tmp=$* echo ${tmp#*$2} }
PS
Не используйте function
поскольку она не является POSIX и фактически совершенно ненужной, если вы уже используете ()
после имени вашей функции.
PPS
Это фактически не имеет никакого отношения к регулярным выражениям, а скорее к глобулярным выражениям . Более формально они известны как Расширения параметров