Grep word dentro de un archivo y luego copie el archivo

9

Tengo una colección de archivos (* .zip, * .txt, * .tar.gz, * .doc, ... etc.). Estos archivos residen dentro de una ruta. Quiero encontrar todos los archivos (* .txt), luego copiar, solo, los archivos de texto que contienen palabras específicas (por ejemplo, LINUX / UNIX).

Ejecuté lo siguiente:

find . -name "*.txt" | grep 'LINUX/UNIX'

Este comando fue capaz de encontrar todos los archivos de texto, luego "grep" filtró los archivos de texto resultantes al enumerar solo los archivos de texto que contienen 'LINUX / UNIX'.

¿Cómo puedo copiar estos archivos finales (es decir, los archivos de texto que contienen 'LINUX / UNIX') a una ruta específica de elección?

Traté de aplicar xargs

find . -name "*.txt" | grep 'LINUX/UNIX' | xargs cp <to a path>

Pero no funcionó


fuente

Respuestas:

21

Tratar:

grep -rl --null --include '*.txt' LINUX/UNIX . | xargs -0r cp -t /path/to/dest

Debido a que este comando usa separación NUL, es seguro para todos los nombres de archivos, incluidos aquellos con nombres difíciles que incluyen espacios en blanco, pestañas o incluso nuevas líneas.

Lo anterior requiere GNU cp. Para MacOS / FreeBSD, intente:

grep -rl --null --include '*.txt' LINUX/UNIX . | xargs -0 sh -c 'cp "$@" /path/to/dest' sh

Cómo funciona:

  1. grep opciones y argumentos

    • -rle dice a grep que busque recursivamente a través de la estructura de directorios. (En FreeBSD, -rseguirá los enlaces simbólicos en los directorios. Esto no se aplica ni a OS / X ni a las versiones recientes de GNU grep).

    • --include '*.txt'le dice a grep que solo devuelva archivos cuyos nombres coincidan con el glob *.txt(incluidos los ocultos como .foo.txto .txt).

    • -l le dice a grep que solo devuelva los nombres de los archivos coincidentes, no la coincidencia misma.

    • --nullle dice a grep que use caracteres NUL para separar los nombres de los archivos. ( --nulles compatible grepcon GNU / Linux , MacOS y FreeBSD pero no con OpenBSD ).

    • LINUX/UNIX le dice a grep que busque solo archivos cuyo contenido incluya la expresión regular LINUX/UNIX

    • .buscar en el directorio actual. Puede omitirlo en versiones recientes de GNU grep, pero luego necesitaría pasar un --terminador de opción cppara protegerse contra los nombres de archivo que comienzan con -.

  2. xargs opciones y argumentos

    • -0 le dice a xargs que espere una entrada separada por NUL.

    • -rle dice a xargs que no ejecute el comando a menos que se encuentre al menos un archivo. (Esta opción no es necesaria ni en BSD ni en OSX y no es compatible con OSX xargs).

    • cp -t /path/to/destcopia los directorios al directorio de destino. ( -trequiere GNU cp)

John1024
fuente
Para Mac OS X, y probablemente BSD, querrás usar --null en lugar de -Z. Además, creo que cp -tes solo para Linux.
Edward Falk
1
@EdwardFalk Buen punto. Gracias. Actualicé para usar --nully agregué una versión para BSD / OSX que no usa cp -t.
John1024
@ StéphaneChazelas Gracias por las mejoras.
John1024
1
OpenBSD grepno tiene --null.
Kusalananda
@Kusalananda Gracias. Respuesta actualizada para tener en cuenta que OpenBSD no es compatible --null.
John1024
14

Más portátil (solo características POSIX):

find . -type f -name '*.txt' -exec grep -q LINUX/UNIX {} \; -exec cp {} /path/to/dest \;
Comodín
fuente
3

El siguiente sh / Bash one liner es otro método, aunque solo funcionará en el directorio actual y no se repite:

for f in ./*.txt; do if grep -l 'LINUX/UNIX' "$f"; then cp "$f" /path/to/dest/; fi; done

La -lopción de grep imprimirá una lista de los archivos que se están copiando, aunque podría usarlos -qsi no desea ver nada en la pantalla.

Arronico
fuente
0

No estoy seguro de por qué la cadena original no funcionó. El siguiente comando funciona para mí.

find / -name (nombre de archivo *) | grep '(nombre de archivo.extención)' | xargs cp -t ./

En mi caso, filename * es una colección de archivos con el mismo nombre con diferentes tipos de archivos (txt, zip, etc.). Hago grep para encontrar solo filename.txt y copiarlo en mi directorio de destino (que es actualmente, ./).

SamL
fuente