Problema com expressão regular no Bash: [^ negate] não parece funcionar

6

Quando executo ls /directory | grep '[^term]' no Bash, recebo uma listagem regular, como se o comando grep fosse ignorado de alguma forma. Eu tentei a mesma coisa com egrep , tentei usá-lo com aspas duplas e simples, mas sem melhores resultados. Quando tento ls /directory | grep '^[term] , obtenho todas as entradas que começam com prazo - conforme esperado.

Eu experimentei esse comando em um editor on-line, onde posso testar meu regex e ele funcionou como deveria. Mas não no Bash. Então funciona em uma simulação, mas não na vida real.

Eu trabalho no Crunchbang Linux 10. Espero que esta seja informação suficiente e estou ansioso para cada dica, porque não conseguir executar em um nível tão básico e perder horas de tempo é realmente frustrante!

    
por erch 31.03.2013 / 22:11

2 respostas

10

Tem certeza de que o que você quer está acontecendo? Quando você executa ls /directory | grep '[^term]' você está essencialmente usando as letras t e r m. Isso significa que, se um arquivo tiver outras letras em seu nome, ele ainda aparecerá na saída de ls . Pegue o seguinte diretório por exemplo:

$ ls
alpha  brave  bravo  charlie  delta

Agora, se eu executar ls |grep '^[brav]' , obtenho o seguinte:

$ ls |grep '^[brav]'
alpha
brave
bravo

Como você pode ver, eu não só obtive brave e bravo como também recebi alpha porque a classe de caracteres [] obterá qualquer letra dessa lista.

Consequentemente, se eu executar ls |grep '[^brav]' , irei obter todos os arquivos que não contenham os caracteres b r a v em qualquer lugar no nome.

$ ls |grep '[^brav]'
alpha
bravo
brave
charlie
delta

Se você perceber que ele incluiu toda a listagem do diretório, porque todos os arquivos tinham pelo menos uma letra que não foi incluída na classe de caracteres.

Então, como Kanvuanza disse, para buscar o inverso de "termo" em oposição aos caracteres t e r m , você deve fazer isso usando grep -v .

Por exemplo:

$ ls |grep -v 'brav'
alpha
charlie
delta

Além disso, se você não quiser que os arquivos que possuem caracteres na classe usem grep -v '[term]' . Isso impedirá a exibição de qualquer arquivo que tenha algum desses caracteres. (Resposta de Kanvuanza)

Por exemplo:

$ ls |grep -v '[brav]'

Como você pode ver, não havia arquivos listados porque todos os arquivos desse diretório incluíam pelo menos uma letra dessa classe.

Adendo:

Eu queria acrescentar que usando o PCRE é possível usar apenas regex para filtrar usando expressões negativas. Para fazer isso, você usaria algo conhecido como regex de look-ahead negativo: (?!<regex>) .

Portanto, usando o exemplo acima, você pode fazer algo assim para obter os resultados desejados sem usar grep flags.

$ ls | grep -P '^(?!brav)'
alpha
charlie
delta

Para desconstruir esse regex, ele primeiro faz a correspondência no início de uma linha ^ e, em seguida, procura sequências que não correspondem a brav a seguir posteriormente. Apenas alpha , charlie e delta correspondem, então, esses são os únicos que são impressos.

    
por 31.03.2013 / 22:44
3

Eu acho que grep -v flag faz o que você quer. Na página do manual :

-v, --invert-match
    Invert the sense of matching, to select non-matching lines.

Você pode usar ls /directory | grep -v [term] para imprimir linhas não correspondentes.

    
por 31.03.2013 / 22:25