Grep: звездочка (*) не всегда работает

Если я найду документ, который содержит следующее:

ThisExampleString

... для выражения This*String или *String, ничего не возвращается. Однако This* возвращает вышеуказанную строку, как и ожидалось.

Не имеет значения, заключено ли выражение в кавычки.

Я думал, что звездочкой обозначено любое количество неизвестных символов? Почему это работает, только если это в начале выражения? Если это предполагаемое поведение, что я использую вместо выражений This*String и *String?

6
задан 22 September 2017 в 06:06

4 ответа

Звездочка в средствах регулярных выражений "соответствует предыдущему элементу 0 или больше раз".

В Вашем особом случае с grep 'This*String' file.txt, Вы пытаетесь сказать, "эй, grep, соответствуйте мне слово Thi, сопровождаемый нижним регистром s нуль или больше раз, сопровождаемый словом String". Нижний регистр s нигде не найти в Example, следовательно grep игнорирует ThisExampleString.

В случае grep '*String' file.txt, Вы говорите "grep, соответствуете мне пустая строка - буквально ничто - предшествование слову String". Конечно, это не то, как ThisExampleString как предполагается, читается. (Существуют другие возможные значения - можно попробовать это и без -E флаг - но ни одно из значений - ничто как то, что Вы действительно хотите здесь.)

Знание этого . означает "любой отдельный символ", мы могли сделать это: grep 'This.*String' file.txt. Теперь команда grep считает его правильно: This сопровождаемый любым символом (думают о нем как о выборе символов ASCII) повторил любое количество раз, сопровождаемое String.

15
ответ дан 22 September 2017 в 16:06
  • 1
    И конечно удаляя /dev/sda2 раздел удалит /dev/sda5. Второй раздел является расширенным, что означает, что он может содержать другой раздел среди него /dev/sda5. – Dark Sinus 24 December 2016 в 00:04

* метасимвол в BRE <глоток> 1 s, ДО <глоток> 1 s и PCRE <глоток> 1 s соответствует 0 или больше происшествиям ранее сгруппированного шаблона (если сгруппированный шаблон предшествует * метасимвол), 0 или больше происшествий предыдущего класса символов (если класс символов предшествует * метасимвол), или 0 или больше происшествий предыдущего символа (если ни сгруппированный шаблон, ни класс символов не предшествуют * метасимвол);

Это означает, что в This*String шаблон, будучи * метасимвол, которому не предшествует или сгруппированный шаблон или класс символов, *, метасимвол соответствует 0 или больше происшествиям предыдущего символа (в этом случае s символ):

% cat infile               
ThisExampleString
ThisString
ThissString
% grep 'This*String' infile
ThisString
ThissString

Для соответствия 0 или больше происшествиям любого символа Вы хотите соответствовать 0 или больше происшествиям . метасимвол, который соответствует любому символу:

% cat infile               
ThisExampleString
% grep 'This.*String' infile
ThisExampleString

* метасимвол в BREs и EREs является всегда "жадным", т.е. он будет соответствовать самому долгому соответствию:

% cat infile
ThisExampleStringIsAString
% grep -o 'This.*String' infile
ThisExampleStringIsAString

Это не может быть желаемым поведением; в случае, если это не, можно включить grep механизм PCRE (использующий -P опция) и добавить ? метасимвол, который при помещении после * и + метасимволы имеют эффект изменения их жадности:

% cat infile
ThisExampleStringIsAString
% grep -Po 'This.*?String' infile
ThisExampleString
<час>

1: Основные Регулярные выражения, Расширенные регулярные выражения и Perl Совместимые Регулярные выражения

8
ответ дан 22 September 2017 в 16:06
  • 1
    Спасибо - I' ve отредактировал вопрос, поскольку я думаю it' s почти там, но все еще совершенно верно! – Ross Dargan 24 December 2016 в 01:11

Одно из объяснения найдено здесь ссылка :

Звездочка" *" не означает того же самого в регулярных выражениях как в wildcarding; это - модификатор, который относится к предыдущему отдельному символу или выражению такой как [0-9]. Звездочка соответствует нулю или больше того, что предшествует ему. Таким образом [A-Z]* соответствия любое количество прописных букв, включая ни один, в то время как [A-Z][A-Z]* соответствия одна или несколько прописных букв.

4
ответ дан 22 September 2017 в 16:06
  • 1
    Я думаю, что Вы используете resize2fs правильно. Я подозреваю, что Ваша проблема возникает из hyper-v, я don' t знают много об этом, I' m не уверенный, что я могу помочь Вам далее... Сообщите мне, находите ли Вы, как зафиксировать это, мне любопытно на предмет этого – Dark Sinus 24 December 2016 в 03:21

* имеет особое значение и как оболочку globbing символ ("подстановочный знак") и как метасимвол регулярного выражения. Необходимо принять обоих во внимание, хотя при заключении в кавычки регулярного выражения затем, можно препятствовать тому, чтобы оболочка рассматривала его особенно, и удостовериться, что оно передает его неизменный grep. Хотя вид подобных концептуально, что * средство для оболочки очень отличается от того, для чего это значит grep.

Сначала обработки оболочки * как подстановочный знак.

Вы сказали:

Включается ли выражение в кавычки, не имеет никакого значения.

Это зависит от того, какие файлы существуют в любом каталоге, Вы, оказывается, находитесь в том, когда Вы выполняете команду. Для шаблонов, которые содержат разделитель каталога /, это может зависеть от того, какие файлы существуют через Вашу целую систему. Необходимо всегда заключать регулярные выражения в кавычки для grep- и одинарные кавычки являются обычно лучшими - если Вы не уверены, что Вы хорошо с девятью типами потенциально удивительных преобразований, которые оболочка иначе выполняет прежде, чем выполниться grep команда.

Когда оболочка встречается с a * символ, который не заключается в кавычки, это берет его для значения "нуля или большего количества любого символа" и заменяет слово, которое содержит его со списком имен файлов, которые соответствуют шаблону. (Имена файлов, которые запускаются с . исключены - если Ваш шаблон сам не запускается с . или Вы настроили свою оболочку для включения их так или иначе.) Это известно как globbing - и также расширением имени файла имен и расширением пути.

Эффект с grep обычно будет то, что первое имя файла соответствия взято в качестве регулярного выражения - даже если для читателя было бы довольно очевидно, что оно не предназначено как регулярное выражение - в то время как все другие имена файлов, перечисленные автоматически от Вашего шарика, взяты в качестве файлов внутри, чтобы искать соответствия. (Вы не видите список - он передается непрозрачно grep.) Вы фактически никогда не хотите, чтобы это произошло.

Причина это иногда - не проблема - и в Вашем особом случае, по крайней мере до сих пор, это не было - это * будет оставлен в покое, если все следующее будет верно:

  1. Не было никаких файлов, имена которых соответствовали.... Или Вы отключили globbing в своей оболочке, обычно с set -f или эквивалент set -o noglob. Но это редко, и Вы, вероятно, знали бы, что сделали это.

  2. Вы используете оболочку, чье поведение по умолчанию состоит в том, чтобы уехать * один, когда нет никаких имен файлов соответствия. Дело обстоит так в Bash, который Вы, вероятно, используете, но не во всех оболочках стиля Границы. (Поведение по умолчанию в популярной оболочке, которая Zsh, например, для шариков любому (a) расширьтесь или (b) продукт ошибка.)... Или Вы изменили это поведение своей оболочки - как это сделано, варьируется через оболочки.

  3. Вы иначе не сказали Вашей оболочке позволять шарикам ничем не быть замененными, когда нет никаких файлов соответствия, ни перестать работать с сообщением об ошибке в этой ситуации. В Bash, который был бы сделан путем включения nullglob или failglob опция оболочки, соответственно.

Можно иногда полагаться на № 2 и № 3, но можно редко полагаться на № 1. A grep команда с неупомянутым шаблоном, который работает теперь, может прекратить работать, когда у Вас есть различные файлы или когда Вы выполняете ее от другого места. Заключите свое регулярное выражение в кавычки, и проблема уходит.

Затем grep обработки команды * как квантор.

Другие ответы - такие как ответы Sergiy Kolodyazhnyy и Косом - также, обращаются к этому аспекту этого вопроса несколько различными способами. Таким образом, я поощряю тех, кто не считал их все же, чтобы сделать так, или прежде или после того, чтобы читать остальную часть этого ответа.

Принятие * действительно добирается до grep - какое заключение в кавычки должно удостовериться-grep затем берет его, чтобы означать, что объект, который предшествует, это может произойти любое количество раз, вместо того, чтобы иметь необходимость произойти точно однажды. Это могло все еще произойти однажды. Или это не могло бы присутствовать вообще. Или это могло быть повторено. Текст, который соответствует любой из тех возможностей, будет подобран.

Что я подразумеваю под "объектом"?

  • Отдельный символ. С тех пор b соответствует литералу b, b* нуль соответствий или больше bs, таким образом ab*c соответствия ac, abc, abbc, abbbc, и т.д.

    Точно так же с тех пор . соответствия любой символ, .* нуль соответствий или больше characters1, таким образом a.*c соответствия ac, akc, ahjglhdfjkdlgjdfkshlgc, даже acccccchjckhcc, и т.д. Или

  • Класс символов. С тех пор [xy] соответствия x или y, [xy]* нуль соответствий или больше символов, где каждый также x или y, таким образом p[xy]*q соответствия pq, pxq, pyq, pxxq, pxyq, pyxq, pyyq, pxxxq, pxxyq, и т.д.

    Это также относится к кратким формам классов символов как \w, \W, \s, и \S. С тех пор \w соответствия любой словесный символ, \w* нуль соответствий или больше словесных символов. Или

  • Группа. С тех пор \(bar\) соответствия bar, \(bar\)* нуль соответствий или больше bars, таким образом foo\(bar\)*baz соответствия foobaz, foobarbaz, foobarbarbaz, foobarbarbarbaz, и т.д.

    С -E или -P опции, grep рассматривает Ваше регулярное выражение как ДО или PCRE соответственно, а не как BRE, и затем группы окружаются ( ) вместо \( \), таким образом Вы использовали бы (bar) вместо \(bar\) и foo(bar)baz вместо foo\(bar\)baz.

man grep дает довольно доступное объяснение BRE и ДО синтаксис в конце, а также перечисляющий все параметры командной строки grep принимает вначале. Я рекомендую, что страница руководства как ресурс, и также документация Grep GNU и это учебное руководство/справочный сайт (который я связал со многими страницами на, выше).

Для тестирования и изучения grep, Я рекомендую назвать его с шаблоном, но никаким именем файла. Затем это берет вход от Вашего терминала. Введите строки; строки, на которые реагируют Вам, являются теми, которые содержали текст Ваш подобранный шаблон. Для выхода нажмите Ctrl+D в начале строки, которая сигнализирует о конце входа. (Или можно нажать Ctrl+C как с большинством программ командной строки.), Например:

grep 'This.*String'

Если Вы используете --color флаг, grep выделит определенные части Ваших строк, которые соответствовали Вашему регулярному выражению, которое очень полезно и для выяснения, что регулярное выражение делает и для нахождения, что Вы смотрите на этот раз, Вы делаете. По умолчанию у пользователей Ubuntu есть псевдоним Bash, который вызывает grep --color=auto работать - который достаточен с этой целью - когда Вы работаете grep из командной строки, таким образом, Вы, вероятно, не должны даже передавать --color вручную.

1 Поэтому .* в регулярном выражении означает что * средства в шарике оболочки. Однако различие - это grep автоматически строки печати, которые содержат Ваше соответствие где угодно в них, таким образом, является обычно ненужным иметь .* вначале или конец регулярного выражения.

1
ответ дан 22 September 2017 в 16:06

Другие вопросы по тегам:

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