Cómo obtener nombres de archivos que contienen solo el texto especificado

Cómo obtener nombres de archivos que contienen solo el texto especificado

Tengo un directorio llamado "etiquetas" en el que hay archivos de texto que contienen etiquetas para "gato" o "perro" o ambos en líneas separadas.
El contenido de los archivos en el directorio de etiquetas es:

cat labels/1.txt
cat

cat labels/2.txt
dog

cat labels/3.txt
cat  
dog

Quiero obtener los nombres de los archivos que contienen únicamente la etiqueta "cat". Intenté el siguiente comando:

ls labels | grep -Rwl "cat"   
labels/1.txt  
labels/3.txt  

Pero este comando devuelve los nombres de aquellos archivos que contienen "cat" o ambos. Pero mi requisito es obtener los nombres de archivos que contengan sólo "gato", no tanto "gato" como "perro".
De manera similar, cuando intento obtener nombres de archivos que contienen únicamente "perro". Si busco de la misma manera, devuelve nombres de archivos que contienen "perro" o ambas etiquetas.

ls labels | grep -Rwl "dog"
labels/2.txt  
labels/3.txt  

Respuesta1

Puede usar grepdos veces: a) para enumerar todos los archivos con cat, luego b) filtrar doglos que contienen. Utilice -ly -L, respectivamente, donde -lenumera los nombres de archivos con coincidencias y -Lnombres de archivos sin coincidencias:

grep -L 'dog' $(grep -l 'cat' <list of files>)

Ver man grep:

-L, --archivos-sin-coincidencia

Suprimir la producción normal; en su lugar, imprima el nombre de cada archivo de entrada del cual normalmente no se habría impreso ninguna salida. El escaneo se detendrá en el primer partido.

-l, --archivos-con-coincidencias

Suprimir la producción normal; en su lugar, imprima el nombre de cada archivo de entrada desde el cual normalmente se habría impreso la salida. El escaneo se detendrá en el primer partido.

Respuesta2

Con GNU grepy xargs( -Rque ya estás usando es una grepextensión de GNU de todos modos, aunque -res preferible allí):

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

Enumeraría los archivos que contienen al menos una catpalabra y ninguna dogpalabra (palabraen ese contexto significa: "no rodeado decaracteres de palabra",caracteres de palabrasiendo caracteres alfanuméricos y guión bajo). Reemplazar -wcon -xpara buscar líneas cuyo contenido completoes cat/ dog.

Respuesta3

Si desea enumerar los nombres de los archivos que contienen "gato" pero no "perro", intente algo como esto, usando findGNU awk(o cualquier otro awkque admita ENDFILEbloques, ya que es una extensión de 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

O podrías usar perlen lugar 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

El resultado de las versiones anteriores de awk y perl se produjo con los siguientes archivos en el labels/subdirectorio:

$ tail labels/*
==> labels/file1.txt <==
cat

==> labels/file2.txt <==
dog

==> labels/file3.txt <==
cat
dog

labels/file1.txtes el único nombre de archivo impreso porque es el único archivo que contiene "gato" y no contiene "perro".

Respuesta4

for f in *; do diff -q <(sort -u "$f") <(echo cat) >/dev/null && echo "$f"; done

información relacionada