Як я рекурсивно переглядаю стиснуті архіви?


16

Я намагаюся з'ясувати, які модулі use Test::Versionв cpan. Тому я звик minicpanце дзеркально. Моя проблема полягає в тому, що мені потрібно повторити файли, які завантажуються, і простежити файли, що знаходяться в архівах. Хтось може сказати мені, як я можу це зробити? бажано таким чином, який підкаже мені, який файл в архіві і в якому рядку.

.

Відповіді:


18

Гаразд, застосуємо філософію unix. Які компоненти цього завдання?

  • Пошук тексту: вам потрібен інструмент для пошуку тексту у файлі, наприклад grep.
  • Рекурсивний: вам потрібен інструмент для пошуку файлів у дереві каталогів, наприклад find.
  • Архів: вам потрібен інструмент для їх читання.

Більшість програм Unix працюють на файлах. Отже, щоб легко працювати з архівними компонентами, вам потрібно отримати доступ до них як файли, іншими словами, вам потрібно отримати доступ до них як каталоги.

У АВФ файлова система являє собою вид файлової системи , де кожен архівний файл /path/to/foo.zipдоступний як каталог ~/.avfs/path/to/foo/zip#. AVFS забезпечує доступ лише для читання до найбільш поширених форматів архівів файлів.

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

Пояснення:

  • Змонтуйте файлову систему AVFS.
  • Шукайте в архіві файли ~/.avfs$PWD, що є переглядом AVFS поточного каталогу.
  • Для кожного архіву виконайте вказаний фрагмент оболонки (з $0= ім'я архіву та $1= шаблон для пошуку).
  • $0#- це перегляд каталогу архіву $0.
  • {\}а не {}потрібно, якщо зовнішні findпідміняють {}внутрішні -exec ;аргументи (деякі роблять це, інші ні).
  • Необов’язково: остаточно відключити файлову систему AVFS.

Або в zsh ≥4,3:

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

Пояснення:

  • ~/.avfs$PWD/**/*.(tgz|tar.gz|zip) відповідає архівам у вигляді AVFS поточного каталогу та його підкаталогів.
  • PATTERN(e\''CODE'\')застосовує CODE до кожного матчу PATTERN. Ім'я відповідного файлу в $REPLY. Встановлення replyмасиву перетворює збіг у список імен.
  • $REPLY\# - це перегляд каталогу архіву.
  • $REPLY\#/**/*.pmвідповідає .pmфайлам в архіві.
  • NГлоб класифікатор робить шаблон розширення порожній список , якщо збігу немає.

це створює іншу цікаву проблему: встановити, а потім відімкнути всі архіви, оскільки частина проблеми полягає в тому, що є 22 к архіви, які потрібно переглядати
xenoterracide

@xenoterracide: Як це проблема? У AVFS у вас є одна точка монтування ( ~/.avfs), і доступ до кожного архіву є автоматичним ( ~/.avfs/path/to/archive.zip\#це звичайний каталог файлової системи AVFS, а не точка монтування). Звичайно, кожен архів, до якого ви отримуєте доступ, означає невелику ефективність, але це суттєво для проблеми.
Жил "ТАК - перестань бути злим"

@gilles лише той факт, що зараз я повинен пройти і зрозуміти, як їх спочатку встановити, що здається трохи поганою ідеєю, краще монтувати їх під час переходу та відключення після обшуку.
ксенотерацид

@xenoterracide: Знову ж таки: ні, вам не потрібно встановлювати їх окремо. Повний робочий процес (крім встановлення AVFS при необхідності) міститься в моїх фрагментах коду.
Жил 'ТАК - перестань бути злим'

@gilles добре, мені доведеться трохи find: missing argument to розібратися в цьому ... бо я отримую -exec'` і багато цього від zshzsh: Input/output error: Data-Maker-0.27
xenoterracide

0

Здається, я можу це зробити так

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

Однак це дає такі результати:

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

що не дуже специфічно для місця в тарболі. Сподіваємось, хтось може придумати кращу відповідь.


0

Дякую за виклик, я придумав:

#!/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

Щойно побачив ваш номер номера рядка. Це, ймовірно, може працювати з деякою комбінацією grep -n та awk, щоб захопити номер рядка. Не можна настільки просто, як grep -H, перелічити ім'я файлу, оскільки це завжди stdin, тому може знадобитися більше рядків.
Кайл Сміт

помилки під час запуску в моїй системі, нескінченно повторювані: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

Також я не усвідомлював, коли вперше розмістив це, що деякі архіви на cpan - це поштові файли.
ксенотеррацид

Гм, я тестував структуру лише файлів .tar.gz - це могло бути більш надійним вживати відповідних дій на основі типу файлу, але це повинно дати гідну вихідну точку.
Кайл Сміт

0

Можливо, моя відповідь комусь допоможе:

#!/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

Після установки p7zip-*ви можете це зробити:

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

Не потрібно використовувати lsперед першою трубкою, який би список стислих файлів не працював. Фінал lessлише покаже ПАТУ про прослуховування життя всередині стислого архіву, але не назву цього.


0

Використовуйте функцію find, щоб знайти всі необхідні файли, і цей zgrep, щоб переглянути стислі файли:

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

Не перевіряв цього на тарботах

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.