Почему `^[ ]{0,}` не работает с linux grep?

Вот несколько вариантов на ту же тему. All создает команду с именем gitoff, которая выполнит git push, за которым следует sudo shutdown -h now, если отправка прошла успешно.

alias gitoff='git push && sudo shutdown -h now'

gitoff () {
    git push && sudo shutdown -h now
}

gitoff () {
    if git push; then
        sudo shutdown -h now
    fi
}

gitoff () {
    if git push; then
        sudo shutdown -h now
    else
        echo >&2 'git push failed, no shutdown'
    fi
}
1
08.05.2019, 14:32
2 ответа

Здесь есть разные проблемы. Прежде всего, выражение ^[ ]wозначает :найти начало строки, затем ровно один пробел, затем w. Так что на самом деле работает отлично. Если вы хотите, чтобы он соответствовал одному или нескольким пробелам, вам нужно добавить классификатор к классу символов [ ]:

  $ grep '^[  ]\+w' text.txt
 whitespace 1
  whitespace 2

+означает «один или несколько». Вариант регулярных выражений по умолчанию, используемый grep, называется базовым регулярным выражением BRE (), и в этом варианте регулярного выражения +необходимо экранировать, поэтому \+выше*. Кроме того, вы можете использовать расширенные регулярные выражения ERE (), передав флаг -E, или PCRE (Perl-совместимые регулярные выражения ), передав флаг -P. С этими вариантами регулярных выражений вам не нужно экранировать +, чтобы он действовал как квантификатор:

$ grep -P '^[  ]+w' text.txt
 whitespace 1
  whitespace 2
$ grep -E '^[  ]+w' text.txt
 whitespace 1
  whitespace 2

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

$ set -x
$ grep ^[ ]{0,}w text.txt
+ grep '^[' ']0w' ']w' text.txt
grep: Invalid regular expression

Во-первых, поскольку между ^[и ]есть пробел, оболочка интерпретирует это как два отдельных аргумента:^[и ]{0,}w. Но {}используются в оболочке для расширения скобок. Например:

$ echo foo{a,b}
fooa foob

Но когда вторая часть расширения пуста, вы получаете:

$ echo foo{a,}
fooa foo

Таким образом, расширение ]{0,}wстановится:

$ echo ]{0,}w
]0w ]w

И в результате, и как вы можете видеть в выводе set -xвыше, эти три аргумента фактически передаются вgrep:

'^[' ']0w' ']w'

Но если вы их цитируете, их нужно экранировать при использовании BRE,точно так же, как +выше:

$ grep '^[ ]\{2\}w' text.txt
  whitespace 2

Последнее замечание :[ ]точно такое же, как , нет смысла использовать класс символов для одного символа.

Объединяя все это, чтобы соответствовать ровно одному пробелу в начале строки, используйте:

$ grep '^ w' text.txt 
 whitespace 1

Чтобы сопоставить один или несколько, используйте:

$ grep '^ \+w' text.txt 
 whitespace 1
  whitespace 2

Или:

$ grep -E '^ +w' text.txt 
 whitespace 1
  whitespace 2

или

$ grep -P '^ +w' text.txt 
 whitespace 1
  whitespace 2

Для соответствия определенному диапазону номеров (, например. 0, 1 или 2 пробела):

$ grep '^ \{0,3\}w' text.txt 
whitespace 0
 whitespace 1
  whitespace 2

или

$ grep -P '^ {0,3}w' text.txt 
whitespace 0
 whitespace 1
  whitespace 2

или

$ grep -E '^ {0,3}w' text.txt 
whitespace 0
 whitespace 1
  whitespace 2

И чтобы соответствовать определенному номеру, либо установите этот номер в {}, как показано выше, либо просто повторите символ N раз:

$ grep '^ \{2\}w' text.txt
  whitespace 2
$ grep '^ w' text.txt
 whitespace 1
$ grep '^  w' text.txt
  whitespace 2

Ивсегда цитируйте ваши регулярные выражения!


*На самом деле, в POSIX BRE +не имеет специального значения, но BRE, реализованный GNU grep, распознает его, если он экранирован.

4
27.01.2020, 23:15

Правильная команда:

Используйтеgrep -E '^[ ]{0,}' text.txt

-E, --extended-regexp Interpret PATTERN as an extended regular expression (ERE, see below).

Причина, по которой не работает:

Не используя одинарные кавычки вокруг регулярного выражения, bash откроет его, и ваша команда станет

grep '^[' ] ]0 text.txt, что переводится как grep с регулярным выражением '^['в файлах ], ]0и text.txt

.

^[неверно, так как [— это специальный символ, который также требует закрывающего символа ]

Почему -Вариант E:

{m,n} является расширенным регулярным выражением, и для его использования grep требуется -параметр E

0
27.01.2020, 23:15

Теги

Похожие вопросы