
Eu tenho um diretório chamado "labels" no qual existem arquivos de texto que contêm rótulos para "gato" ou "cachorro" ou ambos em linhas separadas.
O conteúdo dos arquivos no diretório de rótulos é:
cat labels/1.txt
cat
cat labels/2.txt
dog
cat labels/3.txt
cat
dog
Quero obter os nomes dos arquivos que contêm apenas o rótulo "gato". Eu tentei seguir o comando:
ls labels | grep -Rwl "cat"
labels/1.txt
labels/3.txt
Mas este comando retorna os nomes dos arquivos que contêm “cat” ou ambos. Mas meu requisito é obter os nomes de arquivos que contenham apenas "gato", não "gato" e "cachorro".
Da mesma forma, quando tento obter nomes dos arquivos que contêm apenas "cachorro". Se eu pesquisar da mesma maneira, ele retornará nomes de arquivos que contêm "cachorro" ou ambos os rótulos.
ls labels | grep -Rwl "dog"
labels/2.txt
labels/3.txt
Responder1
Você pode usar grep
duas vezes: a) para listar todos os arquivos com e cat
, em seguida, b) peneirar dog
os que contêm. Use -l
e -L
, respectivamente, onde -l
lista nomes de arquivos com correspondências e -L
nomes de arquivos sem correspondências:
grep -L 'dog' $(grep -l 'cat' <list of files>)
Ver man grep
:
-L, --files-sem correspondência
Suprimir a saída normal; em vez disso, imprima o nome de cada arquivo de entrada do qual normalmente nenhuma saída seria impressa. A varredura irá parar na primeira partida.
-l, --arquivos com correspondências
Suprimir a saída normal; em vez disso, imprima o nome de cada arquivo de entrada do qual a saída normalmente teria sido impressa. A varredura irá parar na primeira partida.
Responder2
Com GNU grep
e xargs
( -R
que você já está usando é uma grep
extensão GNU de qualquer maneira, embora -r
seja preferível lá):
grep -rwlZ cat labels/ | xargs -r0 grep -wL dog
Listaria os arquivos que contêm pelo menos uma cat
palavra e nenhuma dog
palavra (palavranesse contexto, significando: "não cercado porcaracteres de palavras",caracteres de palavrassendo caracteres alfanuméricos e sublinhado). Substitua -w
por -x
para procurar linhas cujo conteúdo completoé cat
/ dog
.
Responder3
Se você quiser listar os nomes dos arquivos que contêm "cat" mas não "dog", tente algo assim, usando find
e GNU awk
(ou qualquer outro awk
que suporte ENDFILE
blocos, pois esta é uma extensão GNU para awk
):
$ find labels/ -type f -exec awk -v IGNORECASE=1 '
/\<cat\>/ { cat = 1 };
/\<dog\>/ { dog = 1 };
ENDFILE {
if (cat == 1 && dog == 0) {
print FILENAME
};
cat = 0;
dog = 0;
}' {} +
labels/file1.txt
Ou você pode usar perl
em vez de awk
:
$ find labels/ -type f -exec perl -l -n -e '
$cat = 1 if m/\bcat\b/i;
$dog = 1 if m/\bdog\b/i;
if (eof) {
print $ARGV if ($cat && ! $dog);
$cat=0;
$dog=0;
}' {} +
labels/file1.txt
A saída das versões awk e perl acima foi produzida com os seguintes arquivos no labels/
subdiretório:
$ tail labels/*
==> labels/file1.txt <==
cat
==> labels/file2.txt <==
dog
==> labels/file3.txt <==
cat
dog
labels/file1.txt
é o único nome de arquivo impresso porque é o único arquivo que contém "cat" e não contém "dog".
Responder4
for f in *; do diff -q <(sort -u "$f") <(echo cat) >/dev/null && echo "$f"; done