Знайдіть рекурсивно всі архівні файли різних архівних форматів та шукайте в них шаблони назв файлів


11

У кращому випадку я хотів би дзвонити так:

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

... так що цей інструмент

  • робить рекурсивне сканування заданого шляху
  • приймає всі файли з підтримуваними архівними форматами, які повинні бути принаймні "найпоширенішими", такими як zip, rar, 7z, tar.bz, tar.gz ...
  • і сканувати список файлів архіву на предмет відповідного шаблону імен (тут *vacation*jpg)

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

Відповіді:


9

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

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

mountavfs

Після цього, якщо /path/to/archive.zipце розпізнаний архів, то ~/.avfs/path/to/archive.zip#це каталог, який, як видається, містить вміст архіву.

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' \;

Пояснення:

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

Або в zsh ≥4,3:

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

Пояснення:

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

9

Якщо ви хочете щось простіше, ніж рішення AVFS, я написав скрипт Python, щоб зробити це під назвою arkfind . Ви насправді можете просто зробити

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

Це буде робити рекурсивно, тому ви можете переглянути архіви всередині архівів на довільну глибину.


Дякую, приємний внесок! Особливо, якщо AVFS не є варіантом.
mdo

Було б чудово, якби він підтримував файли jar.
Chemik

@Chemik - зауважив ! Я трохи більше попрацюю над цим у вихідні :) JAR не повинен бути надто важким, я вважаю, що це справді лише поштовий файл для зовнішнього світу.
detly

@Chemik - я просто спробував це, і він у будь-якому разі повинен підтримувати JAR-файли в його поточному вигляді. Чи можете ви перевірити це, і якщо він не працює, як ви очікували, подайте помилку на сторінку Github? (Я щойно
виправив

1
Так, я бачу зараз, це працює. Ви можете додати "файли JAR" до README :)
Chemik

2

Моє звичайне рішення:

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

Приклад:

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

Результати:

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

Якщо ви хочете лише zip-файл із зверненнями до нього:

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

FILENAME тут використовується двічі, тому ви можете використовувати змінну.

При знаходженні ви можете використовувати ШЛЯХ / ДО / ПОШУК


2

Ще одне рішення, яке працює - це zgrep

zgrep -r filename *.zip

1
Що це за реалізація zgrep? Це не працює з тим, що постачається з GNU gzip( /bin/zgrep: -r: option not supported, zgrep (gzip) 1.6)
Stéphane Chazelas

2

Зручність у користуванні IMHO також має бути основною справою:

 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

а для дьогтю (цей не перевірений ...)

 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

Яка unzipреалізація може мати файли 7z або tar.gz?
Стефан Шазелас

так, це помилка ... виправлено ... слід обов'язково використовувати правильні бінарні файли для правильних типів файлів ... Я просто мав на меті продемонструвати однолінійку. Джи, цей майже добереться до стану готовності як як отримати ...
Йордан Георгієв,

0

libarchive«S bsdtarможе обробляти більшість з цих форматів файлів, так що ви можете зробити:

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

Що ви можете спростити (і вдосконалити, щоб відповідати регістру безвідмовно) з GNU за findдопомогою:

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

Це не друкує шлях до архіву, де ці *vacation*jpgфайли знаходяться. Щоб надрукувати це ім'я, ви можете замінити останній рядок на:

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

який дає вихід:

./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

Або з 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
}

Слід зазначити , що існує ряд інших форматів файлів, які тільки zipабо tgzфайли в маскуванні , як .jarі .docxфайли. Ви можете додати їх у свій шаблон пошуку find/ не важливо для розширення (як, наприклад, розширення не покладається на визначення типу файлу).zshbsdtar

Зауважте, що *vacation*.jpgвище узгоджується на повний шлях до архіву, а не лише ім'я файлу, тому воно буде відповідати, vacation.jpgале і далі vacation/2014/file.jpg.

Для того, щоб відповідати лише ім'ям файлу, одним із фокусів було б використання режиму вилучення , використання -s(підстановки), який використовує регулярні вирази з pпрапором для друку імен файлів, що співпадають, а потім переконайтесь, що жоден файл не вилучається, наприклад:

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

Зауважте, що він виводить список на stderr та додає >>до кожного рядка. У будь-якому випадку, bsdtarяк і більшість tarреалізацій, можна переплутати імена файлів, які відображаються на дисплеї, якщо вони містять символи, такі як нова лінія чи зворотна косою рисою (надається як \nабо \\).

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