grep para várias cadeias de caracteres em arquivos e, em seguida, liste os arquivos na ordem de tamanho

4

Eu estou em uma pasta com muito .txt arquivo, gostaria de encontrar todos os arquivos que contêm stringA e stringB (não necessariamente na mesma linha), então liste esses arquivos na ordem do tamanho (de pequeno a grande)

Eu tentei o seguinte, mas não funciona:

ls -lS | for f in *; do grep -q stringA $f && grep -l stringB $f; done

Alguém tem uma boa ideia?

    
por SoftTimur 06.08.2013 / 20:36

5 respostas

5

Você pode usar GNU find :

find . -maxdepth 1 -exec grep -q stringA {} \; -exec grep -q stringB {} \; \
        -printf '%10s %p\n' | 
    sort -n
    
por 06.08.2013 / 20:41
2

Usando (portável e sem problemas com espaço em nomes de arquivos):

perl -Mautodie -wle '
    for (<"*.txt">) {
        open my $fh, "<", $_;
        my @list = <$fh>;
        close $fh;
        if (grep { /stringA/ } @list and grep { /stringB/ } @list) {
            $h->{$_}->{size} = (stat($_))[8];
        }
    }
    END{
        print join "\n", sort { $h->{$a}->{size} <=> $h->{$b}->{size} } keys %$h;
    }
'
    
por 06.08.2013 / 21:14
2

Com zsh e ferramentas GNU:

grep -lZ -- stringA *.txt(oL) | xargs -r0 grep -l -- stringB
    
por 06.08.2013 / 21:52
2

Método 1

Você pode usar a seguinte cadeia:

$ grep -l stringA * | tr '\n' '
$ grep -lZ stringA * | xargs -0 grep -l stringB | xargs du | sort -nr
' | xargs -0 grep -l stringB | xargs du | sort -nr

O tr converte a saída de grep , de modo que, se algum nome de arquivo incluir espaços, eles serão protegidos daqui para frente. Todo o resto é bem direto. O uso de xargs para executar a saída de um comando anterior até o próximo comando é um padrão típico no Unix.

Você pode ignorar o tr bit e usar a opção grep -Z .

$ grep -lZ stringA * | xargs -0 grep -l stringB | xargs du | sort -nr
9220    stringA99stringB.txt
8196    stringA88stringB.txt
7172    stringA77stringB.txt
6148    stringA66stringB.txt
5124    stringA55stringB.txt
4100    stringA44stringB.txt
3076    stringA33stringB.txt
2052    stringA22stringB.txt
1028    stringA11stringB.txt
4   stringAspacestringB.txt

Exemplo

$ grep -lZ stringA * | xargs -0 grep -l stringB | xargs ls -lS

Método 2

Uma abordagem semelhante, exceto em vez do uso de du | sort , apenas canaliza a saída para ls -lS de forma semelhante à sua abordagem.

$ grep -lZ stringA * | xargs -0 grep -l stringB | xargs ls -lS
-rw-rw-r-- 1 saml saml 9437200 Aug  6 15:15 stringA99stringB.txt
-rw-rw-r-- 1 saml saml 8388624 Aug  6 15:15 stringA88stringB.txt
-rw-rw-r-- 1 saml saml 7340048 Aug  6 15:15 stringA77stringB.txt
-rw-rw-r-- 1 saml saml 6291472 Aug  6 15:15 stringA66stringB.txt
-rw-rw-r-- 1 saml saml 5242896 Aug  6 15:15 stringA55stringB.txt
-rw-rw-r-- 1 saml saml 4194320 Aug  6 15:15 stringA44stringB.txt
-rw-rw-r-- 1 saml saml 3145744 Aug  6 15:15 stringA33stringB.txt
-rw-rw-r-- 1 saml saml 2097168 Aug  6 15:15 stringA22stringB.txt
-rw-rw-r-- 1 saml saml 1048592 Aug  6 15:15 stringA11stringB.txt
-rw-rw-r-- 1 saml saml      32 Aug  6 15:35 stringAspacestringB.txt

Exemplo

$ grep -Pzol "(?s)stringA.*stringB" * | xargs ls -lS

Método 3

Este faz uso da capacidade do grep de usar o mecanismo de expressões regulares do Perl (PCRE).

$ grep -l stringA * | tr '\n' '
$ grep -lZ stringA * | xargs -0 grep -l stringB | xargs du | sort -nr
' | xargs -0 grep -l stringB | xargs du | sort -nr

Esse método é um pouco mais lento porque o arquivo está sendo convertido para que o final das linhas seja finalizado com caracteres nulos ( \n ) em vez de novas linhas ( -P ).

  • -z ativar perl-regexp para grep (uma poderosa extensão de extensões regulares)
  • -o suprime a nova linha no final da linha, substituindo-a por caractere nulo. Isto é, o grep sabe onde é o fim da linha, mas vê a entrada como uma grande linha.
  • -z imprime somente correspondência. Como estamos usando (?s) , o arquivo inteiro é como uma única linha grande, portanto, se houver uma correspondência, o arquivo inteiro será impresso; Desta forma, não vai fazer isso.

no regexp:

  • . ativar PCRE_DOTALL, o que significa que %code% encontra qualquer caractere ou nova linha

Referências

por 06.08.2013 / 21:39
0
 egrep -l '(stringA|stringB)' * | xargs ls -1S

egrep permite expressões regulares, então o acima irá procurar por stringA OR stringB em todos os arquivos, a opção -l diz ao egrep para apenas mostrar os arquivos correspondentes (e suprimir a saída das linhas correspondentes). Piping para xargs ls -1S irá passar todas as correspondências de arquivos para ls -1S . -1 diz ao ls para listar um arquivo por linha e -S diz ao ls para classificar por tamanho de arquivo em vez de por nome.

EDIT Oops, isso é uma OR (leitura errada da pergunta).

Nesse caso, uma adaptação da solução do sputnick para usar dois greps

grep -l stringA * | xargs grep -l stringB | xargs -ls -1S

(pelo menos, ficando em torno de du e sort há um processo a menos:)

    
por 06.08.2013 / 20:45

Tags