В эти дни, изучая 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

"_" это просто курсор, не поймите ошибку :)

кто бы это объяснил? Спасибо

4 ответа4

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 "\\*"
1

Прежде чем grep увидит аргумент командной строки, этот аргумент анализируется оболочкой. Для оболочки * - это подстановочный знак для «всех файлов без точек в текущем каталоге». Поскольку оболочка сначала обрабатывает аргумент, ваша строка превращается в это:

cat abcd | grep abcd otherfile zfile

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

Вместо этого вы можете поместить шаблон для grep в кавычки, чтобы он не обрабатывался оболочкой:

cat abcd | grep "*"

Это лучше, но все же не то, что вы хотите: grep использует регулярные выражения, а не подстановочные знаки в стиле оболочки. Звездочка для grep означает «0..n повторений предыдущего символа» - символ, который вы не указали. Близко, но не сигара.

Если вам нужен "любой" шаблон, вы ищете «0..n повторений произвольного символа». Последний представлен точкой ('.') В регулярных выражениях:

cat abcd | grep ".*"

Это то, что вы искали.

Изменить: другой случай легче объяснить. С grep "" вы ищете пустую строку, которая присутствует в качестве подстроки в любой строке.

0

Bash всегда анализирует * как подстановочные знаки для файла в каталоге. В вашей команде bash выполняет это как

cat abcd | grep abcd file1 file2 ...

так что он показывает только пустой вывод, поскольку это не то, что вы ищете

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .