Jak mogę zapobiec przekazywaniu przez rozszerzenie Bash plików zaczynających się od „-” jako argumentu?

14

Próbuję rekurencyjnie wyszukiwać ciąg, grepale otrzymuję to:

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

Jak mogę uniemożliwić Bashowi przekazywanie plików zaczynających się -od argumentu?

Szef kuchni Tony
źródło
3
Naprawdę nie chcesz uniemożliwić powłoce przekazywania tych plików, prawda? Pytanie brzmi raczej, jak powiedzieć, grepże nie są to opcje.
DonHolgo
11
... dla jasności, bash nie kontroluje, które wyniki są traktowane jako opcje, a nie jako argumenty; jest to pod kontrolą programu odbierającego. Takie samo zachowanie można uzyskać, powiedzmy subprocess.Popen(['grep', '-r', '-e' 'stuff', '--corporate-discount.csv'])w Pythonie, bez niczyjej nuty.
Charles Duffy
1
Literatura pokrewna: Znaki uniksowe Gone Wild o problemach bezpieczeństwa, które mogą być spowodowane przez użycie *poleceń. Wszystkich tych można uniknąć, używając ./*zamiast tego.
Wildcard
1
@Wildcard, używanie --sigilu końca opcji jest również całkowicie uzasadnione; Wytyczne dotyczące składni narzędzi POSIX wymagają, aby były honorowane; patrz wytyczna nr 10. (Oczywiście, nie wszystkie programy są zgodne z wytycznymi POSIX, ale odpowiedzią jest napisanie autorów programów naruszających zasady i / lub wyrzucenie ich z branży).
Charles Duffy,

Odpowiedzi:

43

Po pierwsze, zauważ, że interpretacja argumentów zaczynających się od myślników zależy od uruchamianego programu greplub innego. Powłoka nie ma bezpośredniego sposobu na kontrolowanie tego.

Zakładając, że chcesz przetwarzać takie pliki (i nie ignorować ich całkowicie) grep, wraz z większością programów rozpoznaje --jako wskazujące koniec opcji, więc

grep -r -e "stuff" -- *

zrobi co chcesz. -eIstnieje w przypadku stuffrozpoczyna się -również.

Możesz także użyć:

grep -r -e "stuff"  ./*

Ten ostatni uniknąłby również problemu, gdyby -w bieżącym katalogu był plik wywoływany . Nawet po --separatorze grepinterpretuje -jako znaczenie stdin, podczas ./-gdy plik jest wywoływany -w bieżącym katalogu.

Ikar
źródło
8

Aby zapobiec przekazywaniu plików przez rozszerzenie Bash zaczynając od „-” , możesz użyć:

echo [!-]*

Który działa przenośnie w większości powłok lub, specyficznie dla ksh, bash, zsh:

echo !(-*)

Na przykład: w katalogu z tymi plikami

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

Wyświetla tylko listę (pod warunkiem, że extglobjest aktywna):

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

$ echo [!-]*
a b c d

Ale jeśli chcesz przetworzyć wszystkie pliki, mówiąc grep, aby uniknąć interpretacji plików oznaczonych -opcjami jako, to po prostu dodaj ./:

grep -r "stuff" ./*

Lub, jeśli istnieje gwarancja, że ​​żaden plik o nazwie dokładnie nie -istnieje w wymienionych plikach (grep zinterpretuje plik samotny -jako odczytany ze standardowego wejścia ), możesz użyć:

grep -r -- "stuff" *
Izaak
źródło
Tak, ponieważ pytanie dotyczy bash, powłoki GNU, rozsądne wydaje się założenie, że GNU grep jest dostępny, może zostać zainstalowany lub faktycznie jest używany. @ StéphaneChazelas
Izaak
Tak, a grep -r -- stuff *jest prostsze i działa również z grepami innymi niż GNUish. Więc: dodane, dziękuję. @ StéphaneChazelas
Izaak
@Isaac Nie powiedziałbym, że jest to rozsądne założenie, że „jeśli bash jest dostępny, dostępny jest także GNU grep”. Weźmy na przykład FreeBSD: bash nie jest instalowany domyślnie , co można zainstalować później, ale nie ma to wpływu na grep - pozostaje wersja gred BSD, chyba że GNU grep jest wyraźnie zainstalowany. Ale to drobna dziwaczka. Podoba mi się alternatywne podejście za pośrednictwem extglob, stąd + 1 'odpowiedź
Sergiy Kolodyazhnyy
2
@SergiyKolodyazhnyy, AFAIK, grepna FreeBSD nadal opiera się na GNU grepi nadal ma tę wadę, że opcje są rozpoznawane po braku opcji. Nawet BSD, takie jak OpenBSD, które je przepisały, grepsprawiły, że są kompatybilne z GNU, co umożliwia przenośność wsteczną (i nadal pokazuje takie zachowanie tutaj). W systemie macOS sh to bash, ale oczekiwałbym, że ich grep nie pokaże tego zachowania, ponieważ macOS ma być zgodny z POSIX, nawet bez $ POSIXLY_CORRECT. W każdym razie grep OP jest kompatybilny z GNU, ponieważ daje ten błąd.
Stéphane Chazelas
1
Zobacz także echo [!-]*jako standardowy odpowiednik ksh (lub bash -O extglobs) echo !(-*).
Stéphane Chazelas