Com find -exec grep, como imprimir apenas o nome da base ou dividir o conteúdo do arquivo / linha em linhas separadas?

4

Estou vendo os arquivos de origem. Para PureBasic, na verdade, mas seja qual for a linguagem, há elementos comuns envolvidos. No meu caso, o comando seria as extensões de capa pb , pbi , pbf e pbp :

find . -name "*.pb*" -exec grep -Hnr ... \;

O problema é que isso pode resultar em linhas muito longas e muito contratadas para serem lidas facilmente porque incluem full/path/filename.ext:ln#:contents of that line .

Eu quero fazer uma de duas coisas: cortar completamente o caminho (último / antes do primeiro : ) e sair:

filename.ext:ln#:contents of that line

ou divida a linha para que eu tenha:

full/path/filename.ext:    
ln#:contents of that line

De qualquer maneira, torna os resultados mais legíveis. Você poderia até dividi-lo onde você tinha:

full/path/filename.ext:ln#:  
contents of that line

para maior legibilidade. Eu sou flexível. Pode ser qualquer um desses. Não precisa nem mesmo ser limitado a um comando de uma linha ou a esses comandos específicos.

Eu tentei todas as técnicas que encontrei listadas, envolvendo find , grep e sed , mas não consigo fazer o combo fazer exatamente o que eu quero.

    
por oldefoxx 02.09.2015 / 22:29

4 respostas

1

Eu assumo, a partir de sua descrição, que você está fazendo isso (quebrei em quatro linhas para evitar a rolagem horizontal)

>tmp.txt;
find . -type f -name "*.pb*" \
     -exec grep -Hn pattern "{}" ";" >>tmp.txt;
cat tmp.txt | more

Se você estiver usando o Gnu find, poderá usar -execdir em vez de -exec ; Isso fará com que o comando grep seja executado a partir do diretório do arquivo de destino, com o resultado de que o nome do arquivo será relativo ao diretório em que ele está. (por exemplo, ./filename.ext ). Isso não é bastante o que você está pedindo, mas está bem próximo, e há outras boas razões para usar -execdir .

     -execdir grep -Hn pattern "{}" ";"      # See note 1

Outra opção é usar um shell intermediário para editar o rótulo do nome do arquivo. Isso requer o Gnu grep para a opção --label :

     -exec bash -c 'grep -Hn --label="$(basename "$1")" pattern "$1"' \
           _ "{}" ";"

Isso é um pouco mais longo e funciona muito mais para o sistema operacional, mas elimina o ./ .

Para a segunda opção, você pode canalizar toda a saída através de sed , inserindo uma nova linha após o primeiro (ou segundo) : em cada linha.

find . -type f -name "*.pb*" \
     -exec grep -Hn pattern "{}" ";" |
sed 's/:/&\n/' >>tmp.txt.

ou (segundo cólon):

find . -type f -name "*.pb*" \
     -exec grep -Hn pattern "{}" ";" |
sed 's/:[^:]*:/&\n/' >>tmp.txt.

Notas

  1. Não faz sentido dizer ao grep para fazer uma pesquisa recursiva ( -r ) porque você nunca está dando a ele um diretório como argumento. find já encontrou recursivamente todos os arquivos. Então, removi a opção de todos os meus exemplos.

  2. cat tmp.txt | more é inútil Uso do Cat (UUOC). Apenas use more tmp.txt .

  3. Com o Gnu, encontre substituir ; por + para obter mais eficiência (exceto no exemplo que usa bash -c ).

por 02.09.2015 / 23:12
1

A partir da premissa de que você deseja pesquisar PATTERN em seus arquivos, veja as soluções para cada um dos seus layouts sugeridos:

  1. Remover o componente do nome do caminho principal

    find . -name '*.pb*' -type f -execdir grep -Hn 'PATTERN' {} \; | cut -c3- >tmp.txt
    more tmp.txt
    

    Ao usar execdir , o programa que ele referencia é sempre chamado a partir do diretório de destino, e o nome do caminho do arquivo atual começa com ./ . O cut -c3- simplesmente remove o primeiro ./ do nome do caminho.

  2. Divida a linha com o nome do caminho, seguido pelo número da linha e corresponda

    find . -name '*.pb*' -type f -exec grep -Hn 'PATTERN' {} \; | sed 's/:/:\n/' >tmp.txt
    
  3. Divida a linha com o nome do caminho e o número da linha, seguido da correspondência

    find . -name '*.pb*' -type f -exec grep -Hn 'PATTERN' {} \; | sed 's/^\([^:]*:[^:]*:\)/\n/' >tmp.txt
    

    Aqui, o padrão sed é dividido no segundo cólon (o RE lê como Início no início da linha. Corresponde zero a mais caracteres não-cônicos seguidos por dois-pontos. E novamente. Agora, substitua coincidir com si e, em seguida, uma nova linha ).

Nenhuma dessas soluções funcionará bem se seus nomes de arquivo contiverem dois pontos ou novas linhas.

    
por 03.09.2015 / 00:25
0

Você poderia tentar com awk em vez de grep , por exemplo, imprimir apenas basename:

find . -name '*.pb*' -exec awk 'function basename(file) {
sub(".*/", "", file)
return file
}
/pattern/{
print basename(FILENAME)":"FNR":"$0
}' {} +

e para dividir o conteúdo do caminho / linha:

find . -name '*.pb*' -exec awk '/pattern/{print FILENAME"\n"FNR":"$0}' {} +

ou

find . -name '*.pb*' -exec awk '/pattern/{print FILENAME":"FNR":\n"$0}' {} +

Se você deseja imprimir o nome do arquivo apenas uma vez, seguido por todas as linhas correspondentes nesse arquivo, com dois grep s:

find . -name '*.pb*' -exec grep -l pattern {} \; -exec grep -n pattern {} \;

Estes devem funcionar bem com todos os tipos de nomes de arquivos (mesmo com aqueles que contêm dois pontos) ...

    
por 06.05.2016 / 20:54
0

use grep -l

find . -type f  -exec grep -ilHn --color=always 'searchphrase' {} \;
    
por 23.02.2017 / 18:00

Tags