Làm thế nào để tôi grep đệ quy thông qua tài liệu lưu trữ nén?


16

Tôi đang cố gắng tìm hiểu những mô-đun use Test::Versiontrong cpan. Vì vậy, tôi đã từng minicpanphản chiếu nó. Vấn đề của tôi là tôi cần lặp đi lặp lại qua các tài liệu lưu trữ được tải xuống và grep các tệp trong kho lưu trữ. Bất cứ ai có thể cho tôi biết làm thế nào tôi có thể làm điều này? tốt nhất là theo cách cho tôi biết tập tin nào trong kho lưu trữ và dòng nào trên đó.

(lưu ý: chúng không phải là tất cả tarball, một số là tệp zip)

Câu trả lời:


18

Ok, hãy áp dụng triết lý unix. Các thành phần của nhiệm vụ này là gì?

  • Tìm kiếm văn bản: bạn cần một công cụ để tìm kiếm văn bản trong một tệp, chẳng hạn như grep.
  • Đệ quy: bạn cần một công cụ để tìm kiếm các tệp trong cây thư mục, chẳng hạn như find.
  • Lưu trữ: bạn cần một công cụ để đọc chúng.

Hầu hết các chương trình unix hoạt động trên các tập tin. Vì vậy, để hoạt động dễ dàng trên các thành phần lưu trữ, bạn cần truy cập chúng dưới dạng tệp, nói cách khác, bạn cần truy cập chúng dưới dạng thư mục.

Hệ thống tệp AVFS trình bày một khung nhìn của hệ thống tệp trong đó mọi tệp lưu trữ /path/to/foo.zipcó thể truy cập dưới dạng một thư mục ~/.avfs/path/to/foo/zip#. AVFS cung cấp quyền truy cập chỉ đọc vào hầu hết các định dạng tệp lưu trữ phổ biến.

mountavfs
find ~/.avfs"$PWD" \( -name '*.zip' -o -name '*.tar.gz' -o -name '*.tgz' \) \
     -exec sh -c '
                  find "$0#" -name "*.pm" -exec grep "$1" {\} +
                 ' {} 'Test::Version' \;
fusermount -u ~/.avfs   # optional

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ã được chỉ định (với $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).
  • Tùy chọn: cuối cùng ngắt kết nối hệ thống tập tin AVFS.

Hoặc trong zsh ≥4.3:

mountavfs
grep 'Test::Version' ~/.avfs$PWD/**/*.(tgz|tar.gz|zip)(e\''
     reply=($REPLY\#/**/*.pm(.N))
'\')

Giải thích:

  • ~/.avfs$PWD/**/*.(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 THỰC HIỆN. 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\#/**/*.pmphù hợp với .pmcác tập tin trong kho lưu trữ.
  • Vòng Nloại toàn cầu làm cho mô hình mở rộng thành một danh sách trống nếu không có kết quả khớp.

điều này tạo ra một vấn đề khó khăn khác là phải gắn kết và sau đó ngắt kết nối tất cả các tài liệu lưu trữ, vì một phần của vấn đề là có 22k tài liệu lưu trữ cần được tìm kiếm thông qua
xenoterracide

@xenoterracide: Đó là một vấn đề như thế nào? Với AVFS, bạn có một điểm gắn kết duy nhất ( ~/.avfs) và truy cập vào mỗi kho lưu trữ là tự động ( ~/.avfs/path/to/archive.zip\#là một thư mục thông thường trên hệ thống tệp AVFS, không phải là điểm gắn kết). Chắc chắn, mỗi kho lưu trữ bạn truy cập có nghĩa là một cú đánh hiệu suất nhỏ, nhưng đó thực chất là vấn đề.
Gilles 'SO- ngừng trở nên xấu xa'

@gilles chỉ thực tế là bây giờ tôi phải trải qua và tìm ra cách gắn kết chúng trước, có vẻ như là một ý tưởng tồi, tốt hơn là gắn kết chúng khi tôi đi và tháo gỡ sau khi được tìm kiếm.
xenoterracide

@xenoterracide: Một lần nữa: không, bạn không cần phải gắn chúng riêng lẻ. Quy trình làm việc đầy đủ (ngoài việc cài đặt AVFS nếu cần) nằm trong đoạn mã của tôi.
Gilles 'SO- ngừng trở nên xấu xa'

@gilles tốt Tôi sẽ phải nghiên cứu sâu về vấn đề này một chút ... bởi vì tôi nhận được find: missing argument to -exec'` và rất nhiều thứ này từ zshzsh: Input/output error: Data-Maker-0.27
xenoterracide

0

Dường như tôi có thể làm theo cách này

find authors/ -type f -exec zgrep "Test::Version" '{}' +  

Tuy nhiên, điều này cho kết quả như:

authors/id/J/JO/JONASBN/Module-Info-File-0.11.tar.gz:Binary file (standard input) matches

mà không phải là rất cụ thể cho nơi trong tarball. Hy vọng ai đó có thể đưa ra một câu trả lời tốt hơn.


0

Cảm ơn về thử thách, tôi đã nghĩ ra:

#!/bin/bash
#

# tarballs to check in
find authors/ -type f | while read tarball; do

    # get list of files in tarball (not dirs ending in /):
    tar tzf $tarball | grep -v '/$' | while read file; do       

        # get contents of file and look for string
        tar -Ozxf conform.tar.gz $file | grep -q 'Text::Version' && echo "Tar ($tarball) has matching File ($file)"

    done

done

Chỉ cần nhìn thấy yêu cầu số dòng của bạn. Điều đó có thể có thể hoạt động với một số kết hợp của grep -n và awk để nắm bắt số dòng. Không thể đơn giản như grep -H để liệt kê tên tệp vì nó luôn luôn là stdin, vì vậy có thể cần nhiều dòng hơn.
Kyle Smith

lỗi khi chạy trên hệ thống của tôi, lặp đi lặp lại vô hạn:tar (child): conform.tar.gz: Cannot open: No such file or directory tar (child): Error is not recoverable: exiting now tar: Child returned status 2 tar: Error is not recoverable: exiting now
xenoterracide

Ngoài ra, tôi đã không nhận ra khi lần đầu tiên đăng bài này rằng một số tài liệu lưu trữ trên cpan là các tệp zip.
xenoterracide

Hừm, tôi đã thử nghiệm với cấu trúc chỉ các tệp .tar.gz - có thể mạnh mẽ hơn để thực hiện các hành động phù hợp dựa trên loại tệp, nhưng điều này sẽ cho điểm khởi đầu khá tốt.
Kyle Smith

0

Có lẽ câu trả lời của tôi sẽ hữu ích cho ai đó:

#!/bin/bash

findpath=$(echo $1 | sed -r 's|(.*[^/]$)|\1/|')

# tarballs to check in
find $findpath -type f | while read tarball; do

    # get list of files in tarball (not dirs ending in /):
    if [ -n "$(file --mime-type $tarball | grep -e "application/jar")" ]; then

        jar tf $tarball | grep -v '/$' | while read file; do
            # get contents of file and look for string
            grepout=$(unzip -q -c $tarball $file | grep $3 -e "$2")

            if [ -n "$grepout" ]; then
                echo "*** $tarball has matching file ($file):"
                echo $grepout
            fi

        done

    elif tar -tf $tarball 2>/dev/null; then

        tar -tf $tarball | grep -v '/$' | while read file; do
            # get contents of file and look for string
            grepout=$(unzip -q -c $tarball $file | grep $3 -e "$2")

            if [ -n "$grepout" ]; then
                echo "*** $tarball has matching file ($file):"
                echo $grepout
            fi

        done

    else
        file=""
        grepout=$(grep $3 -e "$2" $tarball)

        if [ -n "$grepout" ]; then
            echo "*** $tarball has matching:"
            echo $grepout
        fi

    fi

done

0

Sau khi cài đặt, p7zip-*bạn có thể làm điều này:

ls | xargs -I {} 7z l {} | grep whatever | less

Bạn không phải sử dụng lstrước đường ống đầu tiên, bất kỳ danh sách nào các tệp nén sẽ hoạt động. Phần cuối cùng lesssẽ chỉ hiển thị PATH của thời gian nghe trong kho lưu trữ được nén, nhưng không hiển thị tên của phần này.


0

Sử dụng find để định vị tất cả các tệp cần thiết và zgrep đó để xem xét các tệp nén:

find <folder> -type f -name "<search criteria[*gz,*bz...]>" -execdir zgrep -in "<grep expression>" '{}' ';'

Không kiểm tra điều này trên tarballs

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.