Grep word em um arquivo e copie o arquivo

9

Eu tenho uma coleção de arquivos (* .zip, * .txt, * .tar.gz, * .doc, ... etc). Esses arquivos residem em um caminho. Quero encontrar todos os arquivos (* .txt) e depois copiar apenas os arquivos de texto que contêm palavras específicas (por exemplo, LINUX / UNIX).

Eu executei o seguinte:

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

Este comando foi capaz de encontrar todos os arquivos de texto e, em seguida, "grep" filtrou os arquivos de texto resultantes, listando apenas os arquivos de texto que contêm 'LINUX / UNIX'.

Como posso copiar esses arquivos finais (ou seja, os arquivos de texto que contêm 'LINUX / UNIX') para um caminho específico de sua escolha?

Eu tentei aplicar xargs

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

Mas não funcionou


fonte

Respostas:

21

Tentar:

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

Como esse comando usa a separação NUL, é seguro para todos os nomes de arquivos, incluindo aqueles com nomes difíceis, que incluem espaços em branco, guias ou até novas linhas.

O acima requer GNU cp. Para MacOS / FreeBSD, tente:

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

Como funciona:

  1. grep opções e argumentos

    • -rdiz ao grep para pesquisar recursivamente através da estrutura de diretórios. (No FreeBSD, -ros links simbólicos serão seguidos nos diretórios. Isso não ocorre no OS / X ou nas versões recentes do GNU grep.)

    • --include '*.txt'diz ao grep para retornar somente arquivos cujos nomes correspondam ao glob *.txt(incluindo nomes ocultos como .foo.txtou .txt).

    • -l diz ao grep para retornar apenas os nomes dos arquivos correspondentes, não a correspondência em si.

    • --nulldiz ao grep para usar caracteres NUL para separar os nomes dos arquivos. ( --nullÉ suportado por grepdebaixo GNU / Linux , MacOS e FreeBSD mas não OpenBSD .)

    • LINUX/UNIX diz ao grep para procurar apenas arquivos cujo conteúdo inclua a expressão regular LINUX/UNIX

    • .procure no diretório atual. Você pode omiti-lo nas versões recentes do GNU grep, mas precisará passar um --terminador de opções para cpse proteger dos nomes de arquivos que começam com -.

  2. xargs opções e argumentos

    • -0 diz aos xargs que esperem entrada separada por NUL.

    • -rdiz ao xargs para não executar o comando, a menos que pelo menos um arquivo tenha sido encontrado. (Esta opção não é necessária no BSD ou no OSX e não é compatível com o OSX xargs.)

    • cp -t /path/to/destcopia os diretórios para o diretório de destino. ( -trequer GNU cp.)

John1024
fonte
Para o Mac OS X e provavelmente o BSD, convém usar --null em vez de -Z. Além disso, acho que cp -té apenas para Linux.
Edward Falk
1
@EdwardFalk Bom argumento. Obrigado. Atualizei para usar --nulle adicionei uma versão para BSD / OSX que não usa cp -t.
John1024
@ StéphaneChazelas Obrigado pelas melhorias.
John1024
1
O OpenBSD grepnão possui --null.
Kusalananda
@Kusalananda Thanks. Resposta atualizada para observar que o OpenBSD não suporta --null.
John1024
14

Mais portável (apenas recursos POSIX):

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

O seguinte liner sh / Bash one é outro método, embora só funcione no diretório atual e não seja recorrente:

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

A -lopção grep imprimirá uma lista dos arquivos que estão sendo copiados, embora você possa usá- -qlo se não quiser ver nada na tela.

Arronical
fonte
0

Não sei por que a string original não funcionou. O comando a seguir funciona para mim.

encontre / -name (nome do arquivo *) | grep '(filename.extention)' | xargs cp -t ./

No meu caso, filename * é uma coleção de arquivos com o mesmo nome e com diferentes tipos de arquivos (txt, zip, etc). Eu grep para descobrir apenas filename.txt e copiá-lo para o diretório de destino (que atualmente é ./).

SamL
fonte