Come posso impedire l'espansione di Bash dal passaggio di file che iniziano con “-” come argomento?


14

Sto cercando di cercare ricorsivamente una stringa con grepma ottengo questo:

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

Come posso impedire a Bash di passare i file a partire da -come argomento?



3
Non vuoi davvero impedire alla shell di passare questi file, vero? La domanda è piuttosto come dire grepche non sono opzioni.
Donolamo

11
... per essere chiari, bash non controlla quali risultati sono trattati come opzioni contro trattati come argomenti; questo è sotto il controllo del programma ricevente. Avresti lo stesso comportamento con, diciamo, subprocess.Popen(['grep', '-r', '-e' 'stuff', '--corporate-discount.csv'])in Python, senza bash da nessuna parte.
Charles Duffy,

1
Lettura correlata: Unix Wildcards Gone Wild , sui problemi di sicurezza che possono essere causati utilizzando i *comandi. TUTTI questi possono essere evitati usando ./*invece.
Wildcard

1
@Wildcard, anche --come sigillo di fine opzioni è perfettamente ragionevole; Le linee guida per la sintassi dell'utilità POSIX richiedono che siano rispettate; vedere la linea guida n. 10. (Certo, non tutti i programmi seguono le linee guida POSIX, ma la risposta è stringere gli autori dei programmi offensivi e / o espellerli dal settore).
Charles Duffy,

Risposte:


43

Innanzitutto, si noti che l'interpretazione degli argomenti che iniziano con trattini dipende dal programma che viene avviato, grepo altro. La shell non ha un modo diretto per controllarlo.

Supponendo che tu voglia elaborare tali file (e non ignorarli completamente) grep, insieme alla maggior parte dei programmi, riconosce --che indica la fine delle opzioni, quindi

grep -r -e "stuff" -- *

farà quello che vuoi. L'ha -elì nel caso stuffinizi con a- pure.

In alternativa, puoi anche utilizzare:

grep -r -e "stuff"  ./*

Quest'ultimo eviterebbe anche il problema se ci fosse un file chiamato -nella directory corrente. Anche dopo il --separatore, grepinterpreta -il significato di stdin, mentre ./-è il file chiamato -nella directory corrente.


8

Per evitare che l'espansione di Bash passi file che iniziano con “-” puoi usare:

echo [!-]*

Che funziona in modo portabile nella maggior parte delle shell, o, specifico per ksh, bash, zsh:

echo !(-*)

Ad esempio: in una directory con questo file

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

Elencherà solo (a condizione che extglobsia attivo):

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

$ echo [!-]*
a b c d

Ma se quello che vuoi è elaborare tutti i file mentre dici a grep per evitare di interpretare i file indicati con -le opzioni as, allora aggiungi semplicemente un ./:

grep -r "stuff" ./*

Oppure, se c'è la garanzia che nessun file chiamato -esista esattamente nei file elencati (grep interpreterà un solitario -come letto da stdin ), puoi usare:

grep -r -- "stuff" *

Sì, poiché la domanda riguarda bash, una shell GNU, sembra ragionevole presumere che un grep GNU sia disponibile, possa essere installato o effettivamente utilizzato. @ StéphaneChazelas
Isaac,

Sì, a grep -r -- stuff *è più semplice e funziona anche con greps non GNUish. Quindi: aggiunto, grazie. @ StéphaneChazelas
Isaac,

@Isaac Non direi che è un presupposto ragionevole "se bash è disponibile, è disponibile anche GNU grep". Prendiamo ad esempio FreeBSD: bash non è installato di default , che può essere installato in seguito, ma non ha alcun effetto su grep: rimane la versione BSD di grep a meno che GNU grep non sia installato esplicitamente. Ma questo è un piccolo pignolo. Mi piace l'approccio alternativo tramite extglob, quindi + 1 ha dato la risposta
Sergiy Kolodyazhnyy,

2
@SergiyKolodyazhnyy, AFAIK, grepsu FreeBSD è ancora basato su GNU grepe ha ancora quel malfunzionamento per cui le opzioni sono riconosciute dopo le non-opzioni. Anche i BSD come OpenBSD che li hanno riscritti grepli hanno resi GNU compatibili per la portabilità all'indietro (e mostrano ancora quel comportamento qui). Su macOS, sh è bash, ma mi aspetto che il loro grep non mostri quel comportamento in quanto macOS dovrebbe essere conforme a POSIX anche senza $ POSIXLY_CORRECT. In ogni caso, il grep dell'OP è compatibile con GNU poiché fornisce quell'errore.
Stéphane Chazelas,

1
Vedi anche echo [!-]*come equivalente standard di ksh (o bash -O extglob') echo !(-*).
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.