Как я могу запретить расширению Bash передавать файлы, начинающиеся с «-» в качестве аргумента?

14

Я пытаюсь рекурсивно искать строку, grepно я получаю это:

$ grep -r "stuff" *
grep: unrecognized option '---corporate-discount.csv'
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.

Как я могу запретить Bash передавать файлы, начинающиеся с -аргумента?

Повар Тони
источник
3
Вы действительно не хотите, чтобы оболочка не передавала эти файлы? Вопрос скорее в том, как сказать grep, что это не варианты.
ДонХолго
11
... чтобы быть ясным, bash не контролирует, какие результаты обрабатываются как параметры, а не как аргументы; это в контроле принимающей программы. Вы получите то же самое поведение, скажем, subprocess.Popen(['grep', '-r', '-e' 'stuff', '--corporate-discount.csv'])в Python, нигде нет.
Чарльз Даффи
1
Связанное чтение: Unix Wildcards Gone Wild , о проблемах безопасности, которые могут быть вызваны использованием *команд. ВСЕ из них можно избежать, используя ./*вместо этого.
Wildcard
1
@Wildcard, использование --в качестве символа конца опций также вполне разумно; Руководство по синтаксису утилит POSIX требует его соблюдения; см. рекомендацию № 10. (Конечно, не все программы следуют рекомендациям POSIX, но ответ состоит в том, чтобы привести в порядок авторов вредоносных программ и / или исключить их из отрасли).
Чарльз Даффи

Ответы:

43

Во-первых, обратите внимание, что интерпретация аргументов, начинающихся с тире, зависит от запускаемой программы grepили другой. Оболочка не имеет прямого способа ее контролировать.

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

grep -r -e "stuff" -- *

будет делать то, что вы хотите. Это -eесть в том случае, если stuffначинается с -.

Кроме того, вы также можете использовать:

grep -r -e "stuff"  ./*

Этот последний также позволит избежать проблемы, если -в текущем каталоге был вызван файл . Даже после --разделителя grepинтерпретируется -как значение stdin, а ./-файл вызывается -в текущем каталоге.

Икар
источник
8

Чтобы запретить расширению Bash передавать файлы, начинающиеся с «-», вы можете использовать:

echo [!-]*

Который работает переносимо в большинстве оболочек, или, специфично для ksh, bash, zsh:

echo !(-*)

Например: в каталоге с этими файлами

$ echo *
a b c ---corporate-discount.csv d -e --option.txt

Список только (при условии extglob, активен):

$ shopt -s extglob
$ echo !(-*)
a b c d

$ echo [!-]*
a b c d

Но если вам нужно обработать все файлы, указав grep, чтобы не интерпретировать файлы, указанные -в параметрах a , то просто добавьте ./:

grep -r "stuff" ./*

Или, если есть гарантия того, что -в списке нет файлов, вызываемых в точности (grep будет интерпретировать одинокий -как прочитанный из stdin ), вы можете использовать:

grep -r -- "stuff" *
Исаак
источник
Да, поскольку вопрос касается bash, оболочки GNU, представляется разумным предположить, что GNU grep доступен, может быть установлен или фактически используется. @ StéphaneChazelas
Исаак
Да, это grep -r -- stuff *проще, и работает также с не GNUish greps. Итак: добавил, спасибо. @ StéphaneChazelas
Исаак
@ Исаак Я бы не сказал, что это разумное предположение "если доступен bash, GNU grep также доступен". Возьмем, к примеру, FreeBSD: bash не установлен по умолчанию , который может быть установлен позже, но это не влияет на grep - он остается BSD-версией grep, если GNU grep явно не установлен. Но это мелкий придира. Мне нравится альтернативный подход с помощью extglob, поэтому я получил +1 ответ
Сергей Колодяжный
2
@SergiyKolodyazhnyy, AFAIK, grepво FreeBSD по-прежнему основан на GNU grepи по-прежнему имеет тот недостаток, при котором опции распознаются после неопций. Даже BSDs как OpenBSD , которые переписаны их grepсделали их GNU совместимы для обратной портативности (и до сих пор показывают , что поведение здесь). В macOS sh - это bash, но я ожидаю, что их grep не покажет, что поведение macOS подразумевает совместимость с POSIX даже без $ POSIXLY_CORRECT. В любом случае, Grep в OP в это GNU-совместимый , так как он дает эту ошибку.
Стефан
1
Смотрите также echo [!-]*как стандартный эквивалент ksh (или bash -O extglobs) echo !(-*).
Стефан