Grep слово в файле, а затем скопировать файл

9

У меня есть коллекция файлов (* .zip, * .txt, * .tar.gz, * .doc, ... и т. Д.). Эти файлы находятся в пути. Я хочу найти все файлы (* .txt), а затем скопировать только текстовые файлы, содержащие определенные слова (например, LINUX / UNIX).

Я запустил следующее:

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

Эта команда смогла найти все текстовые файлы, а затем «grep» отфильтровывает результирующие текстовые файлы, перечисляя только текстовые файлы, которые содержат «LINUX / UNIX».

Как я могу скопировать эти окончательные файлы (т.е. текстовые файлы, которые содержат 'LINUX / UNIX') по определенному пути выбора?

Я пытался подать заявку xargs

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

Но это не сработало


источник

Ответы:

21

Пытаться:

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

Поскольку эта команда использует NUL-разделение, она безопасна для всех имен файлов, в том числе со сложными именами, которые включают пробелы, табуляции или даже переводы строк.

Выше требуется GNU cp. Для MacOS / FreeBSD попробуйте:

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

Как это работает:

  1. grep варианты и аргументы

    • -rсообщает grep рекурсивный поиск по структуре каталогов. (В FreeBSD -rбудут следовать символические ссылки в каталоги. Это не относится ни к OS / X, ни к последним версиям GNU grep.)

    • --include '*.txt'говорит grep, что нужно возвращать только те файлы, имена которых совпадают с глобусом *.txt(включая скрытые, такие как .foo.txtили .txt).

    • -l говорит grep, что нужно возвращать только имена совпадающих файлов, а не само совпадение.

    • --nullговорит grep использовать NUL-символы для разделения имен файлов. ( --nullподдерживается grepв GNU / Linux , MacOS и FreeBSD, но не в OpenBSD .)

    • LINUX/UNIX говорит grep искать только те файлы, содержимое которых включает регулярное выражение LINUX/UNIX

    • .поиск в текущем каталоге. Вы можете опустить его в последних версиях GNU grep, но тогда вам нужно будет передать --терминатор опции cpдля защиты от имен файлов, которые начинаются с -.

  2. xargs варианты и аргументы

    • -0 сообщает Xargs, что следует ожидать ввода NUL.

    • -rговорит xargs не запускать команду, если не найден хотя бы один файл. (Эта опция не нужна ни для BSD, ни для OSX и не совместима с OSX xargs.)

    • cp -t /path/to/destкопирует каталоги в целевой каталог. ( -tтребуется GNU cp.)

John1024
источник
Для Mac OS X и, возможно, BSD, вы захотите использовать --null вместо -Z. Кроме того, я думаю, что cp -tтолько для Linux.
Эдвард Фальк
1
@ EdwardFalk Хороший вопрос. Спасибо. Я обновил, чтобы использовать --nullи добавил версию для BSD / OSX, которая не использует cp -t.
John1024
@ StéphaneChazelas Спасибо за улучшения.
John1024
1
OpenBSD grepне имеет --null.
Кусалананда
@Kusalananda Спасибо. Ответ обновлен, чтобы отметить, что OpenBSD не поддерживает --null.
Джон 1024
14

Более переносимо (только функции POSIX):

find . -type f -name '*.txt' -exec grep -q LINUX/UNIX {} \; -exec cp {} /path/to/dest \;
Wildcard
источник
3

Следующий sh / Bash one liner - это другой метод, хотя он будет работать только в текущем каталоге и не повторяться:

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

-lВозможность Grep напечатает список файлов , которые копируемые, хотя вы могли бы использовать , -qесли вы не хотите , чтобы увидеть что - либо на экране.

Arronical
источник
0

Я не уверен, почему оригинальная строка не работала. Следующая команда работает для меня.

найти / -имя (имя файла *) | grep '(filename.extention)' | xargs cp -t ./

В моем случае filename * - это набор файлов с одинаковыми именами с разными типами файлов (txt, zip и т. Д.). Я делаю grep, чтобы узнать только filename.txt и скопировать его в мой каталог назначения (который в настоящее время ./).

SAML
источник