Você pode usar GNU find
:
find . -maxdepth 1 -exec grep -q stringA {} \; -exec grep -q stringB {} \; \
-printf '%10s %p\n' |
sort -n
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?
Usando perl (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;
}
'
Com zsh
e ferramentas GNU:
grep -lZ -- stringA *.txt(oL) | xargs -r0 grep -l -- stringB
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
$ grep -lZ stringA * | xargs -0 grep -l stringB | xargs ls -lS
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
$ grep -Pzol "(?s)stringA.*stringB" * | xargs ls -lS
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 (
) em vez de novas linhas ( \n
-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 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:)