Регулярные выражения в одинарных кавычках — теряют свою ценность?

Регулярные выражения в одинарных кавычках — теряют свою ценность?

В книге «Изучение оболочки Bash» О'Рейли, которую я читаю, приведен следующий код:

if [ -n "$(echo $1 | grep '^-[0-9][0-9]*$')" ]; then 

   howmany=$1

   shift
   ....
   ....
   etc

Это использует grepутилиту поиска для проверки $1соответствия соответствующему шаблону. Для этого мы предоставляем регулярное выражение ^-[0-9][0-9]*$grep, которое интерпретируется как «начальный тире, за которым следует цифра, необязательно за которой следует одна или несколько цифр». Если совпадение найдено, то grepвернет совпадение, и тест будет истинным, в противном случае grepне вернет ничего, и обработка перейдет к elifтесту.

Обратите внимание, что мы заключили регулярное выражение в одинарные кавычки, чтобы оболочка не интерпретировала символы $ и * и не передала их grep без изменений.

Тогда почему регулярное выражение не '^-[0-9]'теряет своего смысла, как в одинарных кавычках? Обычно все, что находится внутри одинарных кавычек, теряет свой смысл.

Спасибо за помощь.

решение1

Хотя другие уже ответили на ваш конкретный вопрос, я добавлю, что

if [ -n "$(echo $1 | grep '^-[0-9][0-9]*$')" ]; then 

Это неправильный способ проверки соответствия строки регулярному выражению по нескольким причинам:

  1. Вы не можете использовать echoдля произвольных данных
  2. Если оставить расширение параметра без кавычек, как в $1приведенном выше примере, получится оператор split+glob.
  3. grepне сопоставляет регулярное выражение со всем его вводом, а с каждой строкой его ввода. Так что он вернет true, foo\n-0\nbarнапример.
  4. Регулярное выражение может совпадать с нулевой длиной, поэтому в общем случае неправильно проверять, grepпроизводит ли какой-либо вывод (обратите внимание, что подстановка команд удаляет конечные символы новой строки). Лучше использовать grep -qи полагаться на статус выхода grep, а не на статус выхода [, а также избегать подстановки команд.
  5. Обратите внимание, что эту grepкоманду можно упростить доgrep -xE '-[0-9]+'

bash, ksh93и zshиметь выделенный оператор для (расширенного) сопоставления регулярных выражений. Чтобы использовать его переносимо и надежно во всех трех (и bash-3.1), синтаксис такой:

re='^-[0-9]+$'
if [[ $1 =~ $re ]]; then
  echo matches
fi

yashа zshтакже поддержка:

if [ "$1" '=~' '^-[0-9]+$' ]; then
  echo matches
fi

Стандартная команда для выполнения сопоставления строк (базового) регулярного выражения expr:

if expr " $1" : ' -[0-9]\{1,\}$' > /dev/null; then
  echo matches
fi

Обратите внимание, что ^(но не $) подразумевается в expr. Мы также используем этот начальный пробел, чтобы избежать проблем со значениями, $1которые являются exprоператорами.

Также обратите внимание, что если регулярное выражение содержит \(...\), это повлияет на поведение expr.

В целом, лучше использовать awkдругой стандартный/переносимый способ сделать то же самое (обратите внимание, что он awkиспользует расширенные регулярные выражения):

if STRING=$1 RE='^-[0-9]+$' awk '
  BEGIN{exit(ENVIRON["STRING"] !~ ENVIRON["RE"])}'; then
...

Или используйте функцию:

re_match() {
  STRING=$1 RE=$2 awk '
    BEGIN{exit(ENVIRON["STRING"] !~ ENVIRON["RE"])}'
}

if re_match "$1" '^-[0-9]+$'

В этом случае вы также можете добиться этого с помощью стандартной caseконструкции:

case $1 in
  ("" | *[!0-9-]* | [!-]* | - | ?*-*) ;;
  (*) echo match;;
esac

Чтобы использовать grep, вы можете использовать его с --nullопцией (где поддерживается, поскольку это не стандартная опция), чтобы указать ему работать с записями, разделенными NUL, вместо записей, разделенных новой строкой. Поскольку в большинстве оболочек $1не может содержать NUL, это должно быть безопасно:

 if printf %s "$1" | grep --null -xq '-[0-9]+$'; then
   echo match
 fi

решение2

Одинарные кавычки сообщают оболочке, что следует сохранить заключенные в них символы как есть,без какой-либо интерпретации. Строка в кавычках передается как есть grep, без кавычек: при grepпоиске ее аргументов она видит

grep

и

^-[0-9][0-9]*$

и действует на этом основании. (ЧитатьКак запускаются программы(если вам интересно узнать о построении аргументов в Linux.)

bashи grepотличаются. То, как эта команда использует кавычки, гарантирует, что bashне обрабатывает строку, но grepобрабатывает.

решение3

Одинарные кавычки предотвращаютподстановка(позволяя bashинтерпретировать подстановочные знаки, такие как *) и расширение переменной с помощью $. По сути, вы говорите bash"брать буквально эти символы и передавать их в grep". Когда grepвидит их, он построен так, чтобы понимать регулярное выражение, поэтомузатемРегулярное выражение интерпретируется внутри grep.

Более короткая версия: аргументы, заключенные в одинарные кавычки, позволяют избежать обработки в оболочке до того, как аргумент будет передан команде.

решение4

Он теряет свой смысл. grepИспользует почти те же шаблоны регулярных выражений, что и bash.

Связанный контент