Como impedir que a expansão do Bash passe arquivos iniciando com "-" como argumento?

14

Estou tentando pesquisar recursivamente uma string com, grepmas recebo o seguinte:

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

Como impedir que o Bash passe arquivos iniciando -como argumento?

Chef Tony
fonte
3
Você realmente não quer impedir que o shell passe esses arquivos, não é? A questão é como saber grepque elas não são opções.
DonHolgo 17/05/19
11
... para ser claro, o bash não controla quais resultados são tratados como opções versus tratados como argumentos; isso está no controle do programa receptor. Você teria o mesmo comportamento, digamos, subprocess.Popen(['grep', '-r', '-e' 'stuff', '--corporate-discount.csv'])em Python, sem bash em lugar nenhum.
Charles Duffy
1
Leitura relacionada: Wildcards do Unix Gone Wild , sobre problemas de segurança que podem ser causados ​​pelo uso *de comandos. Tudo isso pode ser evitado usando-o ./*.
Curinga
1
@Wildcard, usar --como um sigil de fim de opções também é perfeitamente razoável; As diretrizes de sintaxe do utilitário POSIX exigem que ela seja respeitada; veja a diretriz 10. (Claro, nem todos os programas seguem as diretrizes do POSIX, mas a resposta é encadear os autores dos programas infratores e / ou expulsá-los do setor).
Charles Duffy

Respostas:

43

Primeiro, observe que a interpretação dos argumentos iniciados por traços depende do programa que está sendo iniciado grepou de outro. O shell não tem maneira direta de controlá-lo.

Supondo que você queira processar esses arquivos (e não ignorá-los completamente) grep, juntamente com a maioria dos programas, reconhece --como indicando o fim das opções, portanto

grep -r -e "stuff" -- *

fará o que você quiser. O -eestá lá no caso stuffcomeça com um -também.

Como alternativa, você também pode usar:

grep -r -e "stuff"  ./*

Esse último também evitaria o problema se houvesse um arquivo chamado -no diretório atual. Mesmo após o --separador, grepinterpreta -como significando stdin, enquanto ./-é o arquivo chamado -no diretório atual.

Icaro
fonte
8

Para impedir que a expansão do Bash passe arquivos iniciando com "-", você pode usar:

echo [!-]*

Que funciona de maneira portável na maioria dos shells, ou, específico para ksh, bash, zsh:

echo !(-*)

Por exemplo: em um diretório com esses arquivos

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

Listará apenas (se extglobestiver ativo):

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

$ echo [!-]*
a b c d

Mas se o que você deseja é processar todos os arquivos, enquanto diz ao grep para evitar interpretar os arquivos declarados com as -como opções, basta adicionar um ./:

grep -r "stuff" ./*

Ou, se houver garantia de que nenhum arquivo chamado -exista exatamente nos arquivos listados (o grep interpretará um arquivo -como lido pelo stdin ), você poderá usar:

grep -r -- "stuff" *
Isaac
fonte
Sim, como a pergunta é sobre bash, um shell GNU, parece razoável supor que um GNU grep esteja disponível, possa ser instalado ou esteja sendo realmente usado. @ StéphaneChazelas
Isaac
Sim, a grep -r -- stuff *é mais simples e funciona com greps não-GNUish também. Então: acrescentou, obrigado. @ StéphaneChazelas
Isaac
@ Isaac Eu não diria que é uma suposição razoável "se o bash estiver disponível, o GNU grep também estará disponível". Tomemos, por exemplo, o FreeBSD: bash não é instalado por padrão , o que pode ser instalado posteriormente, mas não há efeito no grep - ele permanece na versão BSD do grep, a menos que o GNU grep seja explicitamente instalado. Mas isso é um pequeno detalhe. I como a abordagem alternativa através extglob, portanto, marcado com +1 a resposta
Sergiy Kolodyazhnyy
2
O @SergiyKolodyazhnyy, AFAIK, grepno FreeBSD ainda é baseado no GNU grepe ainda possui esse erro de caracterização, pelo qual as opções são reconhecidas após as não opções. Até BSDs como o OpenBSD que reescreveram os greptornaram compatíveis com GNU para portabilidade retroativa (e ainda mostram esse comportamento aqui). No macOS, sh é bash, mas eu espero que o grep não mostre que o comportamento como macOS deve ser compatível com POSIX, mesmo sem $ POSIXLY_CORRECT. De qualquer forma, o grep do OP é compatível com GNU, pois fornece esse erro.
Stéphane Chazelas
1
Veja também echo [!-]*como um equivalente padrão de ksh (ou bash -O extglob's) echo !(-*).
Stéphane Chazelas