Wie kann ich verhindern, dass die Bash-Erweiterung Dateien übergibt, die mit "-" als Argument beginnen?

14

Ich versuche rekursiv nach einem String zu suchen grep, bekomme aber folgendes:

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

Wie kann ich verhindern, dass Bash Dateien übergibt, die mit -als Argument beginnen?

Küchenchef Tony
quelle
3
Sie möchten nicht wirklich verhindern, dass die Shell diese Dateien weitergibt, oder? Die Frage ist eher, wie man erkennt, grepdass es sich nicht um Optionen handelt.
DonHolgo
11
... um klar zu sein, kontrolliert bash nicht, welche Ergebnisse als Optionen oder als Argumente behandelt werden. Das liegt in der Kontrolle des empfangenden Programms. Das gleiche Verhalten würde man zum Beispiel subprocess.Popen(['grep', '-r', '-e' 'stuff', '--corporate-discount.csv'])in Python erhalten, wenn nirgendwo eine Bash stattfindet.
Charles Duffy
1
Zugehörige Informationen: Unix-Platzhalter sind veraltet. Hier geht es um Sicherheitsprobleme, die durch die Verwendung von *in-Befehlen verursacht werden können. ALLE diese können vermieden werden, indem man ./*stattdessen verwendet.
Wildcard
1
Die Verwendung von @Wildcard --als End-of-Options-Siegel ist ebenfalls absolut sinnvoll. Nach den Richtlinien für die POSIX-Dienstprogrammsyntax muss diese eingehalten werden. siehe Leitlinie # 10. (Sicher, nicht alle Programme folgen den POSIX-Richtlinien, aber die Antwort ist, die Autoren der beleidigenden Programme zu reihen und / oder sie aus der Branche zu werfen.)
Charles Duffy

Antworten:

43

Beachten Sie zunächst, dass die Interpretation von Argumenten, die mit Bindestrichen beginnen, dem Programm überlassen bleibt, das gerade gestartet wird grep. Die Shell hat keine direkte Möglichkeit, sie zu steuern.

Angenommen, Sie möchten solche Dateien verarbeiten (und sie nicht vollständig ignorieren) grep, erkennt dies zusammen mit den meisten Programmen --als Hinweis auf das Ende der Optionen

grep -r -e "stuff" -- *

werde tun was du willst. Das -egibt es für den Fall, stuffbeginnt mit einem -ebenso.

Alternativ können Sie auch Folgendes verwenden:

grep -r -e "stuff"  ./*

Letzteres würde das Problem auch vermeiden, wenn -im aktuellen Verzeichnis eine Datei aufgerufen würde . Wird auch nach dem --Trennzeichen als stdin grepinterpretiert -, während ./-die Datei -im aktuellen Verzeichnis aufgerufen wird .

icarus
quelle
8

Um zu verhindern, dass die Bash-Erweiterung Dateien übergibt, die mit "-" beginnen , können Sie Folgendes verwenden:

echo [!-]*

Was in den meisten Shells portabel funktioniert, oder speziell in ksh, bash, zsh:

echo !(-*)

Zum Beispiel: in einem Verzeichnis mit diesen Dateien

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

Wird nur auflisten (vorausgesetzt, extglobist aktiv):

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

$ echo [!-]*
a b c d

Wenn Sie jedoch alle Dateien verarbeiten möchten, während Sie grep mitteilen, dass die mit a -als Optionen angegebenen Dateien nicht interpretiert werden sollen, fügen Sie einfach Folgendes hinzu ./:

grep -r "stuff" ./*

Oder wenn garantiert ist, dass -in den aufgelisteten Dateien keine genau aufgerufene Datei vorhanden ist (grep interpretiert eine einsame Datei -als gelesen von stdin ), können Sie Folgendes verwenden:

grep -r -- "stuff" *
Isaac
quelle
Ja, da es sich bei der Frage um Bash handelt, eine GNU-Shell, kann man davon ausgehen, dass ein GNU-grep verfügbar ist, installiert werden könnte oder tatsächlich verwendet wird. @ StéphaneChazelas
Isaac
Ja, a grep -r -- stuff *ist einfacher und funktioniert auch mit Nicht-GNUish-Greps. Also: hinzugefügt, danke. @ StéphaneChazelas
Isaac
@Isaac Ich würde nicht sagen, dass es eine vernünftige Annahme ist "wenn bash verfügbar ist, ist auch GNU grep verfügbar". Nehmen wir zum Beispiel FreeBSD: bash ist nicht standardmäßig installiert , was später installiert werden kann, aber es hat keine Auswirkungen auf grep - es bleibt die BSD-Version von grep, es sei denn, GNU grep wird explizit installiert. Aber das ist ein kleiner Trottel. Ich mag den alternativen Ansatz über extglob, daher + 1'ed die Antwort
Sergiy Kolodyazhnyy
2
@SergiyKolodyazhnyy, AFAIK, grepauf FreeBSD basiert immer noch auf GNU grepund hat immer noch dieses Missfeature, bei dem Optionen nach Nicht-Optionen erkannt werden. Sogar BSDs wie OpenBSD, die sie neu geschrieben haben, grepmachten sie GNU-kompatibel für die Rückwärtsportabilität (und zeigen dieses Verhalten immer noch hier). Unter macOS ist sh bash, aber ich würde erwarten, dass das grep dieses Verhalten nicht zeigt, da macOS POSIX-kompatibel sein soll, auch ohne $ POSIXLY_CORRECT. In jedem Fall wird die grep OP ist GNU-kompatibel , da es diesen Fehler gibt.
Stéphane Chazelas
1
Siehe auch echo [!-]*als Standardäquivalent zu ksh (oder bash -O extglob) echo !(-*).
Stéphane Chazelas