Como obter nomes de arquivos que contêm apenas o texto especificado

Como obter nomes de arquivos que contêm apenas o texto especificado

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 grepduas vezes: a) para listar todos os arquivos com e cat, em seguida, b) peneirar dogos que contêm. Use -le -L, respectivamente, onde -llista nomes de arquivos com correspondências e -Lnomes 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 grepe xargs( -Rque você já está usando é uma grepextensão GNU de qualquer maneira, embora -rseja preferível lá):

grep -rwlZ cat labels/ | xargs -r0 grep -wL dog

Listaria os arquivos que contêm pelo menos uma catpalavra e nenhuma dogpalavra (palavranesse contexto, significando: "não cercado porcaracteres de palavras",caracteres de palavrassendo caracteres alfanuméricos e sublinhado). Substitua -wpor -xpara 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 finde GNU awk(ou qualquer outro awkque suporte ENDFILEblocos, 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 perlem 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

informação relacionada