Comment puis-je empêcher l'expansion de Bash de transmettre des fichiers commençant par «-» comme argument?


14

J'essaie de rechercher récursivement une chaîne avec grepmais j'obtiens ceci:

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

Comment puis-je empêcher Bash de passer des fichiers commençant par -comme argument?



3
Vous ne voulez pas vraiment empêcher le shell de passer ces fichiers, n'est-ce pas? La question est plutôt de savoir comment grepce ne sont pas des options.
DonHolgo

11
... pour être clair, bash ne contrôle pas quels résultats sont traités comme des options vs traités comme des arguments; qui est sous le contrôle du programme récepteur. Vous obtiendriez le même comportement avec, par exemple, subprocess.Popen(['grep', '-r', '-e' 'stuff', '--corporate-discount.csv'])en Python, aucun bash nulle part.
Charles Duffy

1
Lecture connexe: Unix Wildcards Gone Wild , sur les problèmes de sécurité qui peuvent être causés par l'utilisation *de commandes in. Tout cela peut être évité en utilisant à la ./*place.
Wildcard

1
@Wildcard, utiliser --comme sigil de fin d'options est également parfaitement raisonnable; Les directives de syntaxe de l'utilitaire POSIX exigent qu'il soit respecté; voir la ligne directrice n ° 10. (Bien sûr, tous les programmes ne suivent pas les lignes directrices POSIX, mais la réponse est d'enchaîner les auteurs des programmes incriminés et / ou de les expulser de l'industrie).
Charles Duffy

Réponses:


43

Tout d'abord, notez que l'interprétation des arguments commençant par des tirets dépend du programme en cours de démarrage grepou autre. Le shell n'a aucun moyen direct de le contrôler.

En supposant que vous souhaitez traiter ces fichiers (et ne pas les ignorer complètement), grepavec la plupart des programmes, il reconnaît --comme indiquant la fin des options, donc

grep -r -e "stuff" -- *

fera ce que vous voulez. Le -eest là au cas où stuffcommence par un -aussi.

Alternativement, vous pouvez également utiliser:

grep -r -e "stuff"  ./*

Ce dernier éviterait également le problème s'il y avait un fichier appelé -dans le répertoire courant. Même après le --séparateur, grepinterprète -comme signifiant stdin, tandis que ./-le fichier est appelé -dans le répertoire courant.


8

Pour empêcher l'extension Bash de transmettre des fichiers commençant par «-», vous pouvez utiliser:

echo [!-]*

Qui fonctionne de manière portable dans la plupart des shells, ou, spécifique à ksh, bash, zsh:

echo !(-*)

Par exemple: dans un répertoire avec ces fichiers

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

Liste uniquement (à condition que cette option extglobsoit active):

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

$ echo [!-]*
a b c d

Mais si ce que vous voulez est de traiter tous les fichiers tout en disant à grep d'éviter d'interpréter les fichiers indiqués avec -les options as, ajoutez simplement a ./:

grep -r "stuff" ./*

Ou, s'il est garanti qu'aucun fichier appelé -n'existe exactement dans les fichiers répertoriés (grep interprètera un solitaire -comme lu depuis stdin ), vous pouvez utiliser:

grep -r -- "stuff" *

Oui, comme la question concerne bash, un shell GNU, il semble raisonnable de supposer qu'un grep GNU est disponible, pourrait être installé ou est réellement utilisé. @ StéphaneChazelas
Isaac

Oui, a grep -r -- stuff *est plus simple et fonctionne également avec les greps non GNUish. Donc: ajouté, merci. @ StéphaneChazelas
Isaac

@Isaac Je ne dirais pas que c'est une hypothèse raisonnable "si bash est disponible, GNU grep est également disponible". Prenez par exemple FreeBSD: bash n'est pas installé par défaut , qui peut être installé plus tard, mais il n'y a aucun effet sur grep - il reste la version BSD de grep à moins que GNU grep ne soit explicitement installé. Mais c'est une piqûre mineure. J'aime l'approche alternative via extglob, d'où + 1'ed la réponse
Sergiy Kolodyazhnyy

2
@SergiyKolodyazhnyy, AFAIK, grepsur FreeBSD est toujours basé sur GNU grepet présente toujours cette erreur selon laquelle les options sont reconnues après les non-options. Même les BSD comme OpenBSD qui ont réécrit leur ont greprendu GNU compatible pour la portabilité vers l'arrière (et montrent toujours ce comportement ici). Sur macOS, sh est bash, mais je m'attendrais à ce que leur grep ne montre pas que le comportement en tant que macOS est censé être conforme à POSIX même sans $ POSIXLY_CORRECT. Dans tous les cas, le grep de l'OP est compatible GNU car il donne cette erreur.
Stéphane Chazelas

1
Voir aussi echo [!-]*comme un équivalent standard de ksh (ou bash -O extglobde) echo !(-*).
Stéphane Chazelas
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.