
У меня есть файл со следующим содержимым:
sh-4.2$ cat file1
example of multiple
pattern
this is an
example of multipole
sorry multiple
pattern matching
using grep
so the example is the
file itself
-example
-multiple
-bye
tata
!
При поиске "-example" в указанном выше файле команда grep не выдает желаемый вывод. Я знаю, что если шаблон содержит '-', то следует использовать опцию -e:
В первом примере я использовал-примернапрямую, без кавычек:
sh-4.2$ grep -example file1
example of multiple
example of multipole
so the example is the
-example
-примерс одинарными кавычками:
sh-4.2$ grep '-example' file1
example of multiple
example of multipole
so the example is the
-example
-примерс двойными кавычками и экранированными символами
sh-4.2$ grep "\-example" file1
-example
sh-4.2$
решение1
Ну, вы знаете, что шаблон поиска содержит '-', и вы знаете, что когда шаблон поиска содержит '-', вам нужно использовать флаг -e
. Поскольку вы не используете флаг, -e
оболочка интерпретирует ваш "шаблон" как аргумент (и параметр) вместо этого. Вы можете увидеть это с помощью:
$ grep "-foo" file1
grep: oo: No such file or directory
По сути, ваш код grep "-example" file1
сообщает оболочке, что вы хотите запустить ее grep
с -e
аргументом и параметром «xample».
Это та же проблема, с которой мы сталкиваемся, когда пытаемся что-то вроде rm -my-silly-file-name
— это не сработает, и нам нужно использовать что-то вроде rm ./-my-silly-file-name
. Другим обходным решением будет rm -- -my-silly-file-name
. Мы можем использовать эту идиому здесь:
$ grep -- "-example" < file1
-example
Символ «--» сообщает оболочке, что все, что находится после него,нетАргумент.
В качестве альтернативы вы можете просто экранировать «-» с помощью «\», как вы видели:
grep "\-example" file1
В этой статье подробно рассматриваются некоторые детали цитирования.: соответствующая частьПараметры и команды в обратных кавычках, которые должны интерпретироваться оболочкой, заключаются в двойные кавычки.При использовании двойных кавычек содержимое интерпретируется оболочкой.
решение2
Вы «знаете, что если шаблон [начинается с] '-', то следует использовать опцию -e», но не используете ее, когда следует. grep -e -example file1
даст вам ожидаемый результат.
Вот что на самом деле выполняется в каждом из ваших примеров:
grep -example file1
=>grep -e xample file1
(-e необходимо)grep '-example' file1
=>grep -e xample file1
(-e необходимо)grep "\-example" file1
=>grep \-example file1
(-e не обязательно)
решение3
Аргумент, начинающийся с , -
принимается как вариант.
В первых двух случаях первым переданным аргументом grep
является -example
, который grep
понимается как -e xample
( xample
аргумент опции -e
, поэтому ищите xample
).
В третьем случае \-example
передается в grep
. Так как он не начинается с -
, он не воспринимается как опция. Вместо этого он воспринимается как регулярное выражение. Однако поведение для \-
не определено в соответствии с POSIX, поэтому у вас нет гарантии относительно того, что именно ему соответствует. В большинстве grep
реализаций \-
будет соответствовать -
, однако вы можете представить grep
реализации, где \-
может быть специальным оператором (см., например, GNU, grep
где \+
является специальным оператором и не соответствует литералу +
).
Если вы -example
не хотите, чтобы вас рассматривали как вариант, вам необходимо:
grep -- -example file
. Знак--
обозначает конец опций. Все, что после него, не является опцией (поэтому первый аргумент — это шаблон для поиска, а остальные — список файлов для поиска).grep -e -example file
. Здесь-example
принимается как аргумент к-e
варианту.
Вот почему вам стоит привыкнуть писать:
grep -e "$pattern" file
Или
grep -- "$pattern" file
если вы не можете гарантировать, $pattern
что не начнется с -
.
Обратите внимание, что здесь вы также можете написать:
grep '[-]example' file
Хотя см.Выражение в квадратных скобках (без диапазонов), соответствующее неожиданному символу в bashо возможных осложнениях при таком подходе.