Eu tenho vários arquivos e quero descobrir qual deles contém linhas seqüenciais começando com uma determinada string.
Por exemplo, para o seguinte arquivo:
Aaaaaaaaaaaa
Baaaaaaaaaaa
Cxxxxxxxxx
Cyyyyyyyyy
Czzzzzzzzz
Abbbbbbbbbbb
Bbbbbbbbbbbb
Caaaaaa
Accccccccccc
Bccccccccccc
Cdddddd
Ceeeeee
Há mais de uma linha começando com 'C', então eu quero que este arquivo seja encontrado por comando.
Por exemplo, para o seguinte arquivo:
Aaaaaaaaaaaa
Baaaaaaaaaaa
Cxxxxxxxxx
Abbbbbbbbbbb
Bbbbbbbbbbbb
Caaaaaa
Accccccccccc
Bccccccccccc
Cdddddd
Sempre há uma linha começando com 'C', não quero esse arquivo. Pensei em usar um grep
ou um, sed
mas não sei exatamente como fazê-lo. Talvez usando um regexp ^C.*$^C
ou algo parecido. Qualquer ideia ?
C
no seu segundo exemplo.C
?grep
versões mais antigas.Respostas:
Com
pcregrep
:POSIXly:
(embora isso signifique ler todos os arquivos completamente com as
awk
implementações que não suportamnextfile
).Com versões do GNU
grep
até 2.5.4:parece funcionar, mas é por acidente e não é garantido que funcione.
Antes de ser corrigido no 2.6 (por esse commit ), o GNU
grep
havia ignorado que a função de pesquisa de pcre que estava usando corresponderia a todo o buffer atualmente processadogrep
, causando todo tipo de comportamento surpreendente. Por exemplo:corresponderia a um arquivo contendo:
Isso corresponderia a:
Mas isso:
Ou:
não (como
1\n2\n
é através de dois buffers processados porgrep
).Esse comportamento acabou sendo documentado:
Depois de corrigida na versão 2.6, a documentação não foi alterada (uma vez relatei lá ).
fonte
exit
e em-exec \;
vez de nextfile?awk
por arquivo. Você gostaria de fazer isso apenas seawk
não suportarnextfile
e tiver uma grande proporção de arquivos grandes e com linhas correspondentes no início do arquivo.-z
com-P
. Há nenhum\N
, sem-P
, você precisa escrever$'[\01-\011\013-\0377]'
o que só o trabalho em locais C (ver thread.gmane.org/gmane.comp.gnu.grep.bugs/5187 )Com
awk
:Isso imprimirá o conteúdo do arquivo se houver linhas consecutivas começando com a
C
. A expressão(p ~ /^C/ && $1 ~ /^C/)
procurará linhas sucessivas no arquivo e será avaliada como verdadeira se o primeiro caractere em ambas corresponderC
. Se for esse o caso, a linha será impressa.Para encontrar todos os arquivos que possuem esse padrão, você pode executar o awk acima através de um
find
comando:Nesse comando, o
find
+exec
percorrerá cada um dos arquivos e executará umaawk
filtragem semelhante em cada arquivo e imprimirá seu nome viaFILENAME
se a expressão awk for avaliada como verdadeira. Para evitar a impressãoFILENAME
várias vezes para um único arquivo com várias correspondências, aexit
instrução é usada (obrigado @terdon).fonte
C
flag
, apenas peloexit
contrário. Dessa forma, você não precisa continuar processando arquivos depois que uma correspondência foi encontrada.Mais uma opção com o GNU
sed
:Para um único arquivo:
(embora também relate os arquivos que não podem ser lidos).
Para
find
:O problema com arquivos ilegíveis sendo impressos pode ser evitado escrevendo-o:
fonte
sed -n '$q1;/^C/{n;/^C/q}'
?$q1
- força o sed a sair com um erro se o padrão não for encontrado. Ele também terminará com erro se algo estiver errado com o arquivo (é ilegível ou quebrado). Portanto, ele sairá com o status de saída 0 apenas se o padrão for encontrado e será passado para impressão. Parte com/^C/{n;/^C/q
é bastante simples. Se encontrar a sequência que começa com C, lerá a próxima linha e, se também iniciar com C, será encerrada com status de saída zero.Supondo que seus arquivos sejam pequenos o suficiente para serem lidos na memória:
Explicação:
000
: definido\n\n
como separador de registros, ativa o modo de parágrafo, que tratará parágrafos (separados por novas linhas consecutivas) como linhas únicas.-ne
: aplique o script fornecido como argumento-e
a cada linha do (s) arquivo (s) de entrada.$ARGV
: é o arquivo que está sendo processado atualmente/^C[^\n]*\nC/
: correspondaC
no início de uma linha (veja a descrição dossm
modificadores abaixo para saber por que isso funciona aqui) seguido por 0 ou mais caracteres que não são de nova linha, uma nova linha e depois outro C. Em outras palavras, encontre linhas consecutivas começando comC
. *//sm
: esses modificadores de correspondência são (conforme documentado [aqui]):Você também pode fazer algo feio como:
Aqui, o
perl
código substitui novas linhas com%%
isso, supondo que você não tem%%
no seu arquivo de entrada (grande , se é claro), ogrep
irá corresponder linhas consecutivas começando comC
.fonte
SOLUÇÃO:
DEMO:
Primeiro, criaremos uma base de teste:
O acima cria 26 arquivos
/tmp
nomeadosfile1-26
. Em cada arquivo, há 27 ou 28 linhas começando com as letrasa-z
e seguidas pelo restante do alfabeto. Cada terceiro arquivo contém duas linhas consecutivas nas quais o primeiro caractere é duplicado.AMOSTRA:
E quando eu mudo:
para:
Eu recebo...
RESULTADO:
Então, em resumo, a solução funciona assim:
fonte
Este script usa
grep
ecut
para obter números de linhas correspondentes e verifica se há dois números consecutivos. O arquivo é assumido como um nome de arquivo válido passado como o primeiro argumento para o script:fonte