*має особливе значення і як символ глобальної оболонки («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*відповідає нулю або більше bS, таким чином , 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