Como excluir alguns arquivos que não correspondem a certas extensões com o grep?

7

Eu quero mostrar todas as linhas contendo a palavra OK recursivamente de um diretório. Mas há algumas extensões que preciso excluir do resultado:

*~
*.map
*.js except *.debug.js

Eu tentei:

grep -r --exclude={*~,*.map} "OK" /some/dir

Exceto que eu não sei como remover do resultado todos os arquivos% debug .js .

    
por Question Overflow 16.04.2014 / 10:47

5 respostas

6

Gostaria de passar isso por meio de um segundo grep para removê-los:

grep -r --exclude={\*~,\*.map} "OK" bar/ | grep -vP '(?<!debug)\.js'

O -v inverte a correspondência, imprimindo linhas que não correspondem ao padrão e a -P ativa as Expressões regulares compatíveis com Perl, que permitem usar look-behind negativo . Essa regex específica corresponderá a .js , que não é precedida por debug , o que significa que, como estamos invertendo as correspondências, somente os arquivos .js serão impressos.

No entanto, como @QuestionOverflow apontou para os comentários, isso pode ter o efeito colateral indesejado de filtrar linhas que contêm OK e js , pois o grep -v é aplicado ao Toda a saída, não apenas o nome do arquivo. Para evitar isso, basta adicionar dois pontos (é isso que o grep usa para separar nomes de arquivo do conteúdo do arquivo):

grep -r --exclude={*~,*.map} "OK" bar/ | grep -vP '(?<!debug).js:'

Isso ainda falhará se a linha de entrada contiver foo.js: ou se o nome do arquivo contiver : . Então, com certeza, use uma abordagem diferente:

grep -Tr --exclude={*~,*.map} "OK" bar/ | grep -vP '(?<!debug).js\t'

O -T faz com que grep imprima uma tabulação entre o nome do arquivo e o conteúdo do arquivo. Então, se nós simplesmente adicionarmos um \t ao final da regex, ele só será compatível com os nomes dos arquivos, e não com o conteúdo da linha.

Mesmo assim, usando find pode fazer mais sentido, independentemente disso.

    
por 16.04.2014 / 11:00
7

Eu usaria find para localizar os arquivos e canalizar o resultado por meio de xargs :

$ find . -type f \! -name "*~" \
                 \! -name "*.map" \
                 \! \( -name "*.js" -and \! -name "*.debug.js" \) \
         -print0 | xargs -0 grep "OK"

Isso procura por todos os arquivos não correspondentes " *~ ", " *.map " ou " *.js , mas não *.debug.js ".

Usando find , você pode facilmente pesquisar regras bastante complexas, e essa abordagem evita a remoção acidental de falsos positivos, como pode acontecer com o dobro de grep .

    
por 16.04.2014 / 11:13
4

Com zsh , você pode fazer:

setopt extendedglob
grep OK some/dir/**/^(*~|*.map|(^*debug).js)

Desde que a lista de argumentos não seja muito longa, você sempre poderá fazer isso:

printf '%s
setopt extendedglob
grep OK some/dir/**/^(*~|*.map|(^*debug).js)
' some/dir/**/^(*~|*.map|(^*debug).js) | xargs -0 grep OK
    
por 16.04.2014 / 13:34
2

Se você não se importar em ver a saída um pouco fora de ordem (se fizer isso, você pode classificá-la):

grep -r --exclude={*~,*.map,*.js} "OK" /some/dir **/*.debug.js

Isso requer que o seu shell suporte ** para globalização recursiva: zsh sai da caixa, o bash depois de executar shopt -s globstar , o ksh93 depois de executar set -o globstar .

Sem ** support no shell, você pode usar dois comandos grep:

grep -r --exclude={*~,*.map,*.js} "OK" /some/dir
grep -r --include=*.debug.js "OK" /some/dir
    
por 17.04.2014 / 01:43
1

Você pode usar ripgrep . Por padrão, ele ignora arquivos ocultos e respeita seu arquivo .gitignore .

Você pode especificar as regras de inclusão ou exclusão usando os seguintes parâmetros:

-g/--glob GLOB Include or exclude files and directories for searching that match the given glob.

-t/--type TYPE Only search files matching TYPE. Multiple type flags may be provided.

-T/--type-not TYPE Do not search files matching TYPE.

Use the --type-list flag to list all available types.

Aqui estão alguns exemplos simples:

rg -Tjs "OK"                              # Excludes *.js, *.jsx, *.vue files.
rg -tpy "OK"                              # Includes Python files.
rg --type-add 'map:*.map' -tmap PATTERN   # Excludes *.map files.
rg -g '!*.js' -g '*.debug.js' PATTERN     # Excludes *.js apart of *.debug.js.

Aqui está a solução completa para excluir *.~ , *.map , *.js , mas não *.debug.js :

rg -g '*.*' -g '!*.~' -g '!*.map' -g '!*.js' -g '*.debug.js' "OK"

Teste:

$ touch file.~ file.map file.js file.debug.js file.txt file.md
$ rg --files
file.debug.js
file.js
file.map
file.md
file.txt
$ rg -g '*.*' -g '!*.~' -g '!*.map' -g '!*.js' -g '*.debug.js' --files
file.debug.js
file.md
file.txt
    
por 03.05.2018 / 16:32