Як я можу запобігти розширенню 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що вони не є варіантами.
DonHolgo

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, щоб уникнути інтерпретації файлів, зазначених -як параметри, просто додайте ./:

grep -r "stuff" ./*

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

grep -r -- "stuff" *

Так, оскільки питання стосується bash, оболонки GNU, здається, розумним є припущення, що GNU grep є, може бути встановлений або використовується фактично. @ StéphaneChazelas
Ісаак

Так, grep -r -- stuff *простіше, і працює і з не-GNUish greps також. Отже: додано, дякую. @ StéphaneChazelas
Ісаак

@Isaac Я б не сказав, що це обгрунтоване припущення "якщо bash доступний, GNU grep також доступний". Візьмемо для прикладу FreeBSD: bash не встановлений за замовчуванням , який можна встановити пізніше, але на grep це не впливає - це залишається версія BSD grep, якщо явно не встановлено GNU grep. Але це другорядна нітпік. Мені подобається альтернативний підхід через extglob, тому +1 відповіла відповідь
Сергій Колодяжний,

2
@SergiyKolodyazhnyy, AFAIK, grepна FreeBSD все ще базується на GNU grepі досі має таку невдачу, за якою варіанти розпізнаються після не-варіантів. Навіть BSD, такі як OpenBSD, які переписали їх, grepзробили їх GNU сумісним для зворотної портативності (і все ще демонструють таку поведінку тут). У macOS sh є bash, але я б очікував, що їхнє задоволення не покаже, що поведінка як macOS має бути сумісною з POSIX навіть без $ POSIXLY_CORRECT. У будь-якому випадку, Grep в OP в це GNU-сумісний , так як він дає цю помилку.
Стефан Шазелас

1
Дивіться також echo [!-]*як стандартний еквівалент ksh (або bash -O extglob's) echo !(-*).
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.