Чому “grep *” не працює?


0

У ці дні, вивчаючи Linux, я знайшов щось, що мене бентежить:

$ cat abcd
line One
line Two
line Three
$ cat abcd | grep *
$ _                       //nothing greped
$ cat abcd | grep ""
line One
line Two
line Three
$ cat abcd | grep "*"
$ _                       //nothing greped

"_" - це просто курсор, не помиляйтесь :)

хто б це пояснив? Дякую

linux  grep 

Що таке _? На моїй машині, вона дає, _: command not found.
ΔRob

Крім того, що саме ви сподівались cat abcd | grep *надрукувати?
ΔRob

це курсор, просто не

Відповіді:


2

Глобус *розширюється оболонкою до алфавітного списку всіх (не крапкових) файлів у поточному каталозі. Аргументами для цього grepє вираз пошуку та список файлів. Так grep *закінчується використання першого імені файлу як вираз пошуку. Ви шукаєте ім'я першого файлу (як звичайний вираз) в інших файлах.

Grep здійснює пошук у стандартному введенні, лише якщо ви не надаєте явних імен файлів. Побачити:

echo moo | grep . /etc/issue
Handmade Linux for OS/X v 0.001

До речі, *не є правильним регулярним виразом. Як ви виявили, порожній пошуковий вираз відповідає всім рядкам введення. Регулярний вираз, який відповідає всім не порожнім рядкам введення, є .; у регулярному вираженні крапка - це метахарактер, який відповідає одному символу, будь-якому символу, крім нового рядка. Зірка kleene - це суфікс-оператор, який дозволяє робити нульові або більше повторень попереднього регулярного виразу, тому ви часто бачите регулярний вираз .*"що-небудь взагалі", але в цьому контексті він є надмірним, оскільки ви вже зовсім нічого не співпадаєте. з порожнім рядком пошуку.

Нарешті, це вважається поганою формою для catодного файлу. Замість цього cat file | grep ""ви збережете процес і, можливо, якийсь презир , grepпрочитавши файл безпосередньо;grep "" file


1

grep *Збирається робити «універсалізації» розширення проти файлів в поточному каталозі.

Я не можу передбачити, що саме відбудеться, але *, безумовно, відповідатиме імені abcdфайлу. Таким чином, ви можете в кінцевому підсумку шукати "abcd" у abcdфайлі. Або ви можете шукати ім'я першого (лексографічно) першого файла в інших файлах.

Якщо поточний каталог був порожнім, ви закінчили б пошук *. Але це не буде працювати, тому що перший аргумент командного рядка - це регулярний вираз, а "*" - не допустимий регулярний вираз.

Щоб запобігти глобалізації, напишіть це:

$ cat abcd | grep "*"

... але це не має сенсу з наведеної вище причини.

Для пошуку буквального символу "*":

$ cat abcd | grep "\\*"

Найкращий спосіб дізнатися, що трапилося б - спробуватиecho *

Так ... але >> Я << цього не можу зробити. Ось чому мені важко передбачити, що станеться :-)
Стівен C

1

Перш ніж grepпобачити аргумент командного рядка, цей аргумент аналізується оболонкою. Для оболонки *є підстановкою для "всіх неточних файлів у поточному каталозі". Оскільки оболонка спочатку обробляє аргумент, ваш рядок перетворюється на такий:

cat abcd | grep abcd otherfile zfile

(якщо припустити, що ці три файли перебувають у вашому поточному каталозі). Це те, що grepвидно зі своїх аргументів, але це не те, що ви хочете.

Натомість ви можете поставити шаблон для grepлапок, щоб він не оброблявся оболонкою:

cat abcd | grep "*"

Це краще, але все-таки не те, що ви хочете: grepвикористовує регулярні вирази, а не символи символів. Зірочка grepозначає, що "0..n повторень попереднього символу" - символ, який ви не вказали. Близько, але сигари немає.

Якщо ви хочете "будь-який" шаблон, ви шукаєте "0..n повторів довільного характеру". Останній представлений періодом ( '.') у регулярних виразах:

cat abcd | grep ".*"

Це те, що ви шукали.

Правка: Інший випадок легше пояснити. З grep ""вами шукаєте порожню рядок, який присутній як підряд у будь-якому рядку.


За винятком того cat, що марно, а регулярний вираз - марний. partmaps.org/era/unix/award.html
tripleee

@tripleee: Я бачив цю "нагороду", яка кидалася з радістю на такі сайти, як "SO". Я не думаю, що це доречно. Тут ми не говоримо про виробничий код; catв цьому прикладі є родовим дублером для «коли я деякі довільного змісту стандартного введення». Відповідь легше зрозуміти, коли вона не перетворює абстрактний приклад на щось інше, лише задля того, щоб показати свої навички, що дозволяють уникати "зайвих" використання, cat- але дотримується оригінального коду і показує кілька поворотів, які насправді пов’язані з ядром питання.
DevSolar

Я бачу це неправильно; відповідь, яка не в змозі пояснити дотичні та застереження, є менш цінною, ніж відповідь, яка також намагається забезпечити обгрунтованість базового підходу. Це не так вже й погано, як відповіді "спробувати chmod 0777 *", які ви іноді бачите, але в підході "просто виправити симптоми" є спільність.
трійчатка

@triplee: Я не обговорюю три проти чотирьох відступів пробілу, або екіптяни проти ANSI в дужках, ні під час відповіді, якщо це не актуально. Існує тонка грань між тим, що бути багатокорисними і бути поблажливими.
DevSolar

Чудове пояснення! Але все ще виникає питання: чому і як $ cat abcd | grep ""працює? Я маю на увазі, що це просто порожня рядок, чим вона ( "") відрізняється від "*"- при цьому "*"нічого не відповідає?

0

Bash завжди розбирає * як заповнювачі підстановки для файлу в каталозі. У вашій команді bash виконує це як

cat abcd | grep abcd file1 file2 ...

тому він показує лише порожній вихід, оскільки він не є тим, що ви шукаєте


Не завжди. Якщо *цитується, це не буде.
Стівен С
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.