Grep word trong một tập tin sau đó sao chép tập tin


9

Tôi có một bộ sưu tập các tệp (* .zip, * .txt, * .tar.gz, * .doc, ... vv). Những tập tin này nằm trong một đường dẫn. Tôi muốn tìm tất cả các tệp (* .txt), sau đó sao chép, chỉ các tệp văn bản có chứa các từ cụ thể (ví dụ LINUX / UNIX).

Tôi đã chạy như sau:

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

Lệnh này có thể tìm thấy tất cả các tệp văn bản, sau đó "grep" đã lọc các tệp văn bản kết quả bằng cách chỉ liệt kê các tệp văn bản có chứa 'LINUX / UNIX'.

Làm cách nào tôi có thể sao chép các tệp cuối cùng này (tức là các tệp văn bản có chứa 'LINUX / UNIX') vào một đường dẫn cụ thể?

Tôi đã thử áp dụng xargs

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

Nhưng nó không hoạt động


Câu trả lời:


21

Thử:

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

Vì lệnh này sử dụng phân tách NUL, nên an toàn cho tất cả các tên tệp bao gồm cả những tên có tên khó bao gồm khoảng trắng, tab hoặc thậm chí là dòng mới.

Ở trên đòi hỏi GNU cp. Đối với MacOS / FreeBSD, hãy thử:

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

Làm thế nào nó hoạt động:

  1. grep tùy chọn và đối số

    • -rnói với grep để tìm kiếm đệ quy thông qua cấu trúc thư mục. (Trên FreeBSD, -rsẽ theo các liên kết tượng trưng vào các thư mục. Điều này không đúng với cả OS / X hoặc các phiên bản gần đây của GNU grep.)

    • --include '*.txt'yêu cầu grep chỉ trả lại các tệp có tên khớp với toàn cục *.txt(bao gồm các tệp ẩn như .foo.txthoặc .txt).

    • -l nói với grep chỉ trả về tên của các tệp trùng khớp, chứ không phải chính nó.

    • --nullbảo grep sử dụng các ký tự NUL để phân tách tên tệp. ( --nullĐược hỗ trợ bởi grepdưới GNU / Linux , MacOSFreeBSD nhưng không OpenBSD .)

    • LINUX/UNIX yêu cầu grep chỉ tìm các tệp có nội dung bao gồm biểu thức chính LINUX/UNIX

    • .tìm kiếm trong thư mục hiện tại Bạn có thể bỏ qua nó trong các phiên bản gần đây của GNU grep, nhưng sau đó bạn cần phải vượt qua một bộ --kết thúc tùy chọn cpđể bảo vệ chống lại các tên tệp bắt đầu bằng -.

  2. xargs tùy chọn và đối số

    • -0 nói với xargs để mong đợi đầu vào được phân tách bằng NUL.

    • -ryêu cầu xargs không chạy lệnh trừ khi tìm thấy ít nhất một tệp. (Tùy chọn này không cần thiết trên cả BSD hoặc OSX và không tương thích với OSX xargs.)

    • cp -t /path/to/destsao chép các thư mục vào thư mục đích. ( -tyêu cầu GNU cp.)


Đối với Mac OS X và có thể là BSD, bạn sẽ muốn sử dụng - hoàn toàn thay vì -Z. Ngoài ra, tôi nghĩ cp -tlà chỉ dành cho Linux.
Edward Falk

1
@EdwardFalk Điểm tốt. Cảm ơn. Tôi đã cập nhật để sử dụng --nullvà thêm phiên bản cho BSD / OSX không sử dụng cp -t.
John1024

@ StéphaneChazelas Cảm ơn bạn đã cải tiến.
John1024

1
OpenBSD grepkhông có --null.
Kusalananda

@Kusalananda Cảm ơn. Trả lời cập nhật để lưu ý rằng OpenBSD không hỗ trợ --null.
John1024

14

Đáng tin cậy hơn (chỉ tính năng POSIX):

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

3

Lớp lót sh / Bash sau đây là một phương thức khác, mặc dù sẽ chỉ hoạt động trong thư mục hiện tại và không lặp lại:

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

Các -ltùy chọn để grep sẽ in một danh sách các file đang được sao chép, mặc dù bạn có thể sử dụng -qnếu bạn không muốn nhìn thấy bất cứ điều gì trên màn hình.


0

Tôi không chắc tại sao chuỗi gốc không hoạt động. Theo lệnh làm việc cho tôi.

tìm / -name (tên tệp *) | grep '(tên tệp. nội dung)' | xargs cp -t ./

Trong trường hợp của tôi, tên tệp * là tập hợp các tệp có cùng tên với các loại tệp khác nhau (txt, zip, v.v.). Tôi làm grep để tìm ra filename.txt và sao chép nó vào thư mục đích của tôi (hiện đang là ./).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.