Tìm đệ quy tất cả các tệp lưu trữ có định dạng lưu trữ đa dạng và tìm kiếm chúng cho các mẫu tên tệp


11

Tốt nhất tôi muốn có một cuộc gọi như thế này:

$searchtool /path/to/search/ -contained-file-name "*vacation*jpg"

... để công cụ này

  • thực hiện quét đệ quy của đường dẫn đã cho
  • lấy tất cả các tệp có định dạng lưu trữ được hỗ trợ, ít nhất phải là "phổ biến nhất" như zip, rar, 7z, tar.bz, tar.gz ...
  • và quét danh sách tập tin của kho lưu trữ cho mẫu tên được đề cập (ở đây *vacation*jpg)

Tôi biết cách sử dụng công cụ tìm kiếm, tar, giải nén và tương tự. Tôi có thể kết hợp chúng với tập lệnh shell nhưng tôi đang tìm một giải pháp đơn giản có thể là trình bao một lớp hoặc công cụ chuyên dụng (gợi ý cho các công cụ GUI được hoan nghênh nhưng giải pháp của tôi phải dựa trên dòng lệnh).

Câu trả lời:


9

(Chuyển thể từ Làm thế nào để tôi đệ quy grep qua kho lưu trữ nén? )

Cài đặt AVFS , một hệ thống tệp cung cấp quyền truy cập trong suốt vào kho lưu trữ. Trước tiên hãy chạy lệnh này một lần để thiết lập chế độ xem hệ thống tệp của máy mà bạn có thể truy cập tài liệu lưu trữ như thể chúng là các thư mục:

mountavfs

Sau này, nếu /path/to/archive.ziplà một kho lưu trữ được công nhận, thì đó ~/.avfs/path/to/archive.zip#là một thư mục có vẻ chứa nội dung của kho lưu trữ.

find ~/.avfs"$PWD" \( -name '*.7z' -o -name '*.zip' -o -name '*.tar.gz' -o -name '*.tgz' \) \
     -exec sh -c '
                  find "$0#" -name "*vacation*.jpg"
                 ' {} 'Test::Version' \;

Giải thích:

  • Gắn kết hệ thống tập tin AVFS.
  • Tìm tệp lưu trữ trong ~/.avfs$PWD, đó là dạng xem AVFS của thư mục hiện tại.
  • Đối với mỗi kho lưu trữ, hãy thực thi đoạn mã shell được chỉ định (with $0= tên lưu trữ và $1= mẫu để tìm kiếm).
  • $0#là giao diện thư mục của kho lưu trữ $0.
  • {\}thay vì {}cần thiết trong trường hợp các findthay thế bên ngoài {}bên trong các -exec ;đối số (một số làm điều đó, một số thì không).

Hoặc trong zsh ≥4.3:

mountavfs
ls -l ~/.avfs$PWD/**/*.(7z|tgz|tar.gz|zip)(e\''
     reply=($REPLY\#/**/*vacation*.jpg(.N))
'\')

Giải thích:

  • ~/.avfs$PWD/**/*.(7z|tgz|tar.gz|zip) phù hợp với tài liệu lưu trữ trong chế độ xem AVFS của thư mục hiện tại và các thư mục con của nó.
  • PATTERN(e\''CODE'\')áp dụng MÃ cho mỗi trận đấu của MẪU. Tên của tệp phù hợp là trong $REPLY. Đặt replymảng biến trận đấu thành một danh sách các tên.
  • $REPLY\# là giao diện thư mục của kho lưu trữ.
  • $REPLY\#/**/*vacation*.jpgphù hợp với *vacation*.jpgcác tập tin trong kho lưu trữ.
  • Vòng Nloại toàn cầu làm cho mẫu mở rộng thành một danh sách trống nếu không có kết quả khớp.

9

Nếu bạn muốn một cái gì đó đơn giản hơn là giải pháp AVFS, tôi đã viết một tập lệnh Python để thực hiện nó được gọi là arkfind . Bạn thực sự có thể làm

$ arkfind /path/to/search/ -g "*vacation*jpg"

Nó sẽ làm điều này một cách đệ quy, vì vậy bạn có thể xem tài liệu lưu trữ bên trong kho lưu trữ đến một độ sâu tùy ý.


Cảm ơn, đóng góp tốt đẹp! Đặc biệt nếu AVFS không có tùy chọn.
mdo

Sẽ thật tuyệt nếu nó hỗ trợ các tệp jar.
Chemik

@Chemik - lưu ý ! Tôi sẽ làm thêm một chút vào cuối tuần này :) JAR không quá khó, tôi tin rằng nó thực sự chỉ là một tệp zip với thế giới bên ngoài.
gièm pha

@Chemik - Tôi mới thử nó và nó sẽ hỗ trợ các tệp JAR ở dạng hiện tại. Bạn có thể kiểm tra nó không, và nếu nó không hoạt động như bạn mong đợi, hãy báo lỗi trên trang Github? (Tôi vừa sửa một lỗi, vì vậy hãy chắc chắn cập nhật bản sao của bạn.)
gièm pha

1
Có tôi thấy bây giờ, nó hoạt động. Bạn có thể thêm "tệp JAR" vào README :)
Chemik

2

Giải pháp thông thường của tôi :

find -iname '*.zip' -exec unzip -l {} \; 2>/dev/null | grep '\.zip\|DESIRED_FILE_TO_SEARCH'

Thí dụ:

find -iname '*.zip' -exec unzip -l {} \; 2>/dev/null | grep '\.zip\|characterize.txt'

Resuls giống như:

foozip1.zip:
foozip2.zip:
foozip3.zip:
    DESIRED_FILE_TO_SEARCH
foozip4.zip:
...

Nếu bạn chỉ muốn tệp zip có lượt truy cập vào nó:

find -iname '*.zip' -exec unzip -l {} \; 2>/dev/null | grep '\.zip\|FILENAME' | grep -B1 'FILENAME'

FILENAME ở đây được sử dụng hai lần, vì vậy bạn có thể sử dụng một biến.

Với tìm kiếm, bạn có thể sử dụng PATH / TO / TÌM KIẾM


2

Một giải pháp khác hiệu quả là zgrep

zgrep -r filename *.zip

1
Những gì thực hiện zgrepđó là? Điều đó không hoạt động với cái được vận chuyển với GNU gzip( /bin/zgrep: -r: option not supported, zgrep (gzip) 1.6)
Stéphane Chazelas

2

IMHO thân thiện với người dùng cũng là một điều trong bash:

 while read -r zip_file ; do echo "$zip_file" ; unzip -l "$zip_file" | \
 grep -i --color=always -R "$to_srch"; \
 done < <(find . \( -name '*.7z' -o -name '*.zip' \)) | \
 less -R

và cho tar (cái này chưa được kiểm tra ...)

 while read -r tar_file ; do echo "$tar_file" ; tar -tf  "$tar_file" | \
 grep -i --color=always -R "$to_srch"; \
 done < <(find . \( -name '*.tar.gz' -o -name '*.tar' \)) | \
 less -R

Việc unziptriển khai nào có thể xử lý các tệp 7z hoặc tar.gz?
Stéphane Chazelas

vâng, đó là một lỗi ... đã sửa ... người ta chắc chắn nên sử dụng các tệp nhị phân chính xác cho các loại tệp chính xác ... Tôi chỉ nhằm mục đích chứng minh một-liner .. jee cái này gần như sẽ sẵn sàng đến trạng thái sẵn sàng như cách nhận ...
Yordan Georgiev

0

libarchive's bsdtarcó thể xử lý hầu hết các định dạng tập tin, vì vậy bạn có thể làm:

find . \( -name '*.zip' -o     \
          -name '*.tar' -o     \
          -name '*.tar.gz' -o  \
          -name '*.tar.bz2' -o \
          -name '*.tar.xz' -o  \
          -name '*.tgz' -o     \
          -name '*.tbz2' -o    \
          -name '*.7z' -o      \
          -name '*.iso' -o     \
          -name '*.cpio' -o    \
          -name '*.a' -o       \
          -name '*.ar' \)      \
       -type f                 \
       -exec bsdtar tf {} '*vacation*jpg' \; 2> /dev/null

Mà bạn có thể đơn giản hóa (và cải thiện để khớp với trường hợp không nhạy cảm) với GNU findvới:

find . -regextype egrep \
       -iregex '.*\.(zip|7z|iso|cpio|ar?|tar(|\.[gx]z|\.bz2)|tgz|tbz2)' \
       -type f \
       -exec bsdtar tf {} '*vacation*jpg' \; 2> /dev/null

Điều đó không in đường dẫn của kho lưu trữ nơi các *vacation*jpgtệp được tìm thấy mặc dù. Để in tên đó, bạn có thể thay thế dòng cuối cùng bằng:

-exec sh -ac '
   for ARCHIVE do
     bsdtar tf "$ARCHIVE" "*vacation*jpg" |
       awk '\''{print ENVIRON["ARCHIVE"] ": " $0}'\''
   done' sh {} + 2> /dev/null

cung cấp một đầu ra như:

./a.zip: foo/blah_vacation.jpg
./a.zip: bar/blih_vacation.jpg
./a.tar.gz: foo/blah_vacation.jpg
./a.tar.gz: bar/blih_vacation.jpg

Hoặc với zsh:

setopt extendedglob # best in ~/.zshrc
for archive (**/*.(#i)(zip|7z|iso|cpio|a|ar|tar(|.gz|.xz|.bz2)|tgz|tbz2)(.ND)) {
  matches=("${(f@)$(bsdtar tf $archive '*vacation*jpg' 2> /dev/null)"})
  (($#matches)) && printf '%s\n' "$archive: "$^matches
}

Lưu ý rằng có một số định dạng tệp khác chỉ ziphoặc tgzcác tệp được ngụy trang như .jarhoặc .docxtệp. Bạn có thể thêm chúng vào mẫu find/ zshtìm kiếm của mình , bsdtarkhông quan tâm đến tiện ích mở rộng (như trong, nó không dựa vào tiện ích mở rộng để xác định loại tệp).

Lưu ý rằng *vacation*.jpgở trên được khớp trên đường dẫn thành viên lưu trữ đầy đủ, không chỉ tên tệp, vì vậy nó sẽ khớp trên vacation.jpgmà còn trên vacation/2014/file.jpg.

Để chỉ khớp với tên tệp, một mẹo là sử dụng chế độ giải nén , sử dụng -s(thay thế) sử dụng biểu thức chính quy với pcờ để in tên của các tệp phù hợp và sau đó đảm bảo không có tệp nào được trích xuất, như:

bsdtar -'s|.*vacation[^/]*$||' -'s|.*||' -xf "$archive"

Lưu ý rằng nó sẽ xuất danh sách trên stderr và nối >>vào mỗi dòng. Trong mọi trường hợp, bsdtargiống như hầu hết các tartriển khai có thể xáo trộn tên tệp được hiển thị nếu chúng chứa một số ký tự như dòng mới hoặc dấu gạch chéo ngược (được hiển thị dưới dạng \nhoặc \\).

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.