*
має особливе значення і як символ глобальної оболонки («wildcard»), і як метахарактер регулярного вираження . Ви повинні взяти до уваги обидва, хоча якщо ви цитуєте свій регулярний вираз, то ви можете запобігти спеціальній обробці оболонки і переконатися, що вона передає їй незмінний вміст grep
. Хоча це щось подібне концептуально, те, що *
означає для оболонки, зовсім інше, ніж це означає grep
.
Спочатку оболонку розглядають *
як підстановку.
Ти сказав:
Незалежно від того, чи є вираз укладеним у лапки, немає значення.
Це залежить від того, які файли існують у будь-якому каталозі, в якому ви трапляєтесь під час запуску команди. Для моделей, що містять роздільник каталогів /
, це може залежати від того, які файли існують у всій вашій системі. Ви завжди повинні цитувати регулярні вирази для grep
- а одиночні лапки, як правило, найкращі - якщо ви не впевнені, що ви добре з дев'ятьма типами потенційно дивовижних перетворень, які обов`язково виконує оболонка перед виконанням grep
команди.
Коли оболонка стикається з *
символом, який не цитується , він вважає, що це означає «нуль або більше будь-якого символу» і замінює слово, яке містить його, списком імен файлів, що відповідають шаблону. (Імена файлів, які починаються з .
, виключаються - якщо тільки ваш шаблон не починається з .
або ви не налаштували оболонку, щоб все-таки включити їх.) Це відомо як глобування - а також за розширенням імені файлів та розширенням імені шляху .
Ефект з grep
, як правило, полягає в тому, що перше ім'я файлу, що відповідає, приймається як регулярний вираз - навіть якщо людському читачеві було б цілком очевидно, що він не мається на увазі як регулярний вираз - в той час як усі інші імена файлів автоматично перераховані з вашого glob приймаються як файли, всередині яких для пошуку відповідностей. (Ви не бачите списку - він непрозоро передається grep
.) Ви практично ніколи не хочете, щоб це сталося.
Причина цього іноді не є проблемою - а у вашому конкретному випадку, принаймні, поки що це не було - це те *
, що залишиться в спокої, якщо всі наступні дійсні :
Там не було ні одного файлу , чиї імена збігаються. ... Або ви відключили глобулінг у своїй оболонці, як правило, з set -f
еквівалентом або set -o noglob
. Але це нечасто, і ви, мабуть, знаєте, що це зробили.
Ви використовуєте оболонку, поведінка за замовчуванням якої залишається в *
спокої, коли немає відповідних імен файлів. Це той випадок у Bash, який ви, мабуть, використовуєте, але не у всіх оболонках у стилі Борна. (Поведінка за замовчуванням у популярній оболонці Zsh, наприклад, для глобусів або (a) розширюється, або (b) створює помилку.) ... Або ви змінили таку поведінку вашої оболонки - як це робиться, змінюється поперек снарядів.
Ви іншим чином не сказали своїй оболонці дозволяти замінювати глобуси нічим, коли немає відповідних файлів, а також не виходити з повідомлення про помилку в цій ситуації. У Bash це було б зроблено, включивши опціюnullglob
або failglob
shell відповідно.
Іноді можна покластися на №2 та №3, але рідко можна покластися на №1. grep
Команда з некотируваних малюнком , який працює в даний час може перестати працювати , якщо у вас є різні файли або при запуску його з іншого місця. Цитуйте своє регулярне вираження, і проблема відходить.
Тоді як grep
команда розглядає *
як квантор.
Інші відповіді - такі як Сергій Колодяжний та Кос - також вирішують цей аспект цього питання дещо по-різному. Тож я закликаю тих, хто ще їх не читав, перед чи після прочитання решти цієї відповіді.
Якщо припустити, що це *
дійсно змушує зафіксувати - що цитування повинно забезпечити - grep
тоді це означає, що елемент, який передує йому, може виникати будь-яку кількість разів , а не мати місце саме один раз . Це все-таки могло відбутися один раз. Або може взагалі не бути присутнім. Або це могло повторитися. Текст, який відповідає будь-якій із цих можливостей, буде відповідати.
Що я маю на увазі під «предметом»?
Єдиний персонаж . Так b
матчі буквальний b
, b*
відповідає нулю або більше b
S, таким чином , ab*c
відповідає ac
, abc
, abbc
, abbbc
і т.д.
Аналогічно, так як .
відповідає будь-якому символу , .*
відповідає нулю або більше символів 1 , при цьому 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\)*
відповідає нулю або більше bar
років, таким чином , foo\(bar\)*baz
відповідає foobaz
, foobarbaz
, foobarbarbaz
, foobarbarbarbaz
і т.д.
За допомогою параметрів -E
або -P
трафік grep
розглядає ваш регулярний вираз відповідно як ERE або PCRE , а не як BRE , а потім групи оточуються (
)
замість \(
\)
, а потім ви використовуєте (bar)
замість \(bar\)
і foo(bar)baz
замість foo\(bar\)baz
.
man grep
дає досить доступне пояснення синтаксису BRE та ERE в кінці, а також перелік усіх параметрів командного рядка, grep
прийнятих на початку. Я рекомендую цю сторінку керівництва як ресурс, а також GNU Grep документацію та цей підручник / довідковий сайт (який я пов’язував із низкою сторінок вище).
Для тестування та навчання grep
я рекомендую викликати його з малюнком, але без імені файлу. Потім він бере вхід з вашого терміналу. Введіть рядки; рядки, які перегукуються з вами, - це ті, що містять текст, з яким узгоджується ваш шаблон. Щоб вийти, натисніть Ctrl+ Dна початку рядка, який сигналізує про закінчення введення. (Або ви можете натиснути Ctrl+, Cяк у більшості програм командного рядка.) Наприклад:
grep 'This.*String'
Якщо ви використовуєте --color
прапор, grep
буде виділено конкретні частини ваших рядків, які відповідають вашому регулярному вираженню, що дуже корисно як для з'ясування того, що робить регулярний вираз, так і для пошуку того, що ви шукаєте, як тільки ви це зробите. За замовчуванням користувачі Ubuntu мають псевдонім Bash, який викликає grep --color=auto
запуск - цього достатньо для цієї мети - коли ви запускаєте grep
з командного рядка, тому вам, ймовірно, навіть не потрібно проходити --color
вручну.
1 Отже, .*
в регулярному виразі означає, що *
означає в глобулі оболонки. Однак різниця полягає в тому, що grep
автоматично друкується рядки, які містять вашу відповідність будь-де в них, тому зазвичай .*
на початку або в кінці регулярного виразу зазвичай не потрібно .
* != any number of unknown characters