grep ficando confuso com nomes de arquivos com traços

3

Estou com um problema em que o grep fica confuso quando o diretório contém um arquivo que começa com traços.

Por exemplo, tenho um arquivo chamado " ------.js ". Quando faço algo como grep somestring * , recebo o erro:

grep: unrecognized option '------.js'
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.

Esse parece ser o tipo de pergunta que seria feita em toda a Internet, mas não consigo encontrar nada.

Eu posso resolver manualmente o problema com algo como find . | while read f; do grep MYSTRING "$f"; done
, mas estou pensando se há uma solução mais simples / mais robusta.

Estou executando o Arch Linux.

    
por aggregate1166877 14.05.2017 / 04:48

4 respostas

6

Como complemento à resposta de Romeu, note que

grep pattern --whatever

é exigido pelo POSIX para procurar por padrão no arquivo --whatever . Isso porque nenhuma opção deve ser reconhecida após argumentos não-opcionais (aqui pattern ).

O GNU grep nessa instância não é compatível com POSIX. Ele pode ser feito em conformidade, passando a variável de ambiente POSIXLY_CORRECT (com qualquer valor) para seu ambiente.

Esse é o caso da maioria dos utilitários e utilitários GNU usando uma implementação GNU ou compatível de getopt() / getopt_long() para analisar argumentos de linha de comando.

Há exceções óbvias, como env , em que env VAR=x grep --version obtém a versão de grep , não env . Outra exceção notável é o shell GNU ( bash ), no qual nem o interpretador nem qualquer um de seus componentes internos aceitam opções após argumentos não opcionais. Mesmo seu getopts não pode analisar as opções da maneira GNU.

De qualquer forma, POSIXLY_CORRECT não salvará você se fizer

grep -e pattern *.js

(lá, pattern não é um argumento não opcional, é passado como um argumento para a opção -e , então mais opções são permitidas depois disso).

Portanto, é sempre uma boa ideia marcar o final das opções com: quando você não pode garantir que o que vem depois não comece com - (ou + com algumas ferramentas):

grep -e pattern -- *.js
grep -- pattern *.js

ou use:

grep -e pattern ./*.js

(observe que grep -- pattern * não ajudará se houver um arquivo chamado - , enquanto grep pattern ./* funcionará. grep -e "$pattern" deve ser usado em vez de grep "$pattern" caso o $pattern possa começar com - ).

Houve uma tentativa em meados dos anos 90 de ter bash sendo capaz de informar getopt() quais argumentos (normalmente os resultantes de uma expansão glob) não deveriam ser tratados como opções (por meio de um ambiente _<pid>_GNU_nonoption_argv_flags_ variável), mas isso foi removido já que causava mais problemas do que resolvido.

    
por 14.05.2017 / 09:09
6

Você pode tentar a opção do grep que diz "fim dos parâmetros"

grep -- <string> <filename>

Isto irá informar ao grep para ignorar os próximos traços como parâmetros e encadeá-los como próximos elementos na linha de comando

    
por 14.05.2017 / 04:54
3

Só para postar uma resposta TLDR com a outra correção óbvia ,

grep -e pattern ./*.js

Isso funciona para comandos que não apresentam a opção -- ; apesar de ser bastante amplamente suportado, nem todos os comandos lidam com isso.

(Observe também o -e , que similarmente funciona para desambiguar um padrão que começa com um traço. Você pode também trabalhar com algo como [-]pattern , mas isso não funciona com grep -F ; e se o padrão for fornecido pelo usuário, é melhor não mexer com ele.)

Depois de "(quase) sempre citar suas variáveis," esta é provavelmente a segunda pegadinha mais comum na programação shell - as correspondências curinga e os dados fornecidos pelo usuário podem e ocasionalmente conterão um traço inicial, então é melhor você estar preparado.

    
por 14.05.2017 / 12:14
2

Você soluciona com find ,

find . | while read f; do grep MYSTRING "$f"; done

pode ser melhorado:

find . -maxdepth 1 -type f -exec grep -H "MYSTRING" {} +

Não há nada "não robusto" sobre isso.

Ele resolve os problemas com os traços no nome do arquivo, pois find invocará grep com o nome do arquivo precedido pelo caminho ./ .

As outras duas soluções são separar as opções do nome do arquivo usando -- na linha de comando (que indicará à rotina de análise da linha de comando que não há mais opções para analisar), ou especificar o valor absoluto ou relativo. caminho para o arquivo.

    
por 14.05.2017 / 08:39