Grep word di dalam file lalu salin file tersebut

9

Saya memiliki koleksi file (* .zip, * .txt, * .tar.gz, * .doc, ... dll). File-file ini berada dalam jalur. Saya ingin menemukan semua file (* .txt), lalu salin, hanya, file teks yang berisi kata-kata tertentu (misalnya LINUX / UNIX).

Saya menjalankan yang berikut:

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

Perintah ini dapat menemukan semua file teks, kemudian "grep" memfilter file teks yang dihasilkan dengan mendaftar hanya file teks yang berisi 'LINUX / UNIX'.

Bagaimana saya bisa menyalin file terakhir ini (yaitu file teks yang berisi 'LINUX / UNIX') ke jalur pilihan tertentu?

Saya mencoba melamar xargs

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

Tapi itu tidak berhasil


sumber

Jawaban:

21

Mencoba:

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

Karena perintah ini menggunakan pemisahan-NUL, aman untuk semua nama file termasuk yang memiliki nama sulit yang termasuk kosong, tab, atau bahkan baris baru.

Di atas membutuhkan GNU cp. Untuk MacOS / FreeBSD, coba:

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

Bagaimana itu bekerja:

  1. grep opsi dan argumen

    • -rmemberitahu grep untuk mencari secara rekursif melalui struktur direktori. (Pada FreeBSD, -rakan mengikuti symlink ke direktori. Ini tidak berlaku untuk OS / X atau versi terbaru GNU grep.)

    • --include '*.txt'memberitahu grep untuk hanya mengembalikan file yang namanya cocok dengan bola dunia *.txt(termasuk yang tersembunyi seperti .foo.txtatau .txt).

    • -l memberitahu grep untuk hanya mengembalikan nama file yang cocok, bukan pertandingan itu sendiri.

    • --nullmemberitahu grep untuk menggunakan karakter NUL untuk memisahkan nama file. ( --nulldidukung oleh di grepbawah GNU / Linux , MacOS dan FreeBSD tetapi tidak OpenBSD .)

    • LINUX/UNIX memberitahu grep untuk mencari hanya file yang isinya termasuk regex LINUX/UNIX

    • .cari di direktori saat ini. Anda dapat menghilangkannya di versi terbaru GNU grep, tetapi kemudian Anda harus melewati --terminator opsi cpuntuk menjaga dari nama file yang dimulai dengan -.

  2. xargs opsi dan argumen

    • -0 memberitahu xargs untuk mengharapkan input yang dipisahkan oleh NUL.

    • -rmemberitahu xargs untuk tidak menjalankan perintah kecuali jika setidaknya satu file ditemukan. (Opsi ini tidak diperlukan pada BSD atau OSX dan tidak kompatibel dengan OSX xargs.)

    • cp -t /path/to/destmenyalin direktori ke direktori target. ( -tmembutuhkan GNU cp.)

John1024
sumber
Untuk Mac OS X, dan mungkin BSD, Anda akan ingin menggunakan --null bukan -Z. Juga, saya pikir cp -thanya Linux.
Edward Falk
1
@EdwardFalk Poin bagus. Terima kasih. Saya memperbarui untuk menggunakan --nulldan menambahkan versi untuk BSD / OSX yang tidak digunakan cp -t.
John1024
@ StéphaneChazelas Terima kasih atas peningkatannya.
John1024
1
OpenBSD greptidak punya --null.
Kusalananda
@ Kusalananda Terima kasih. Jawaban diperbarui untuk dicatat bahwa OpenBSD tidak mendukung --null.
John1024
14

Lebih mudah dibawa (hanya fitur POSIX):

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

Sh / Bash one liner berikut adalah metode lain, meskipun hanya akan berfungsi di direktori saat ini, dan tidak berulang:

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

The -lpilihan untuk grep akan mencetak daftar file yang sedang disalin, meskipun Anda bisa menggunakan -qjika Anda tidak ingin melihat apa-apa di layar.

Arronikal
sumber
0

Saya tidak yakin mengapa string asli tidak berfungsi. Perintah berikut bekerja untuk saya.

find / -name (nama file *) | grep '(filename.extention)' | xargs cp -t ./

Dalam kasus saya nama file * adalah kumpulan file dengan nama yang sama dengan jenis file yang berbeda (txt, zip, dll). Saya memang grep hanya mengetahui namafile.txt dan menyalinnya ke direktori tujuan saya (yang saat ini, ./).

SamL
sumber