Найдите рекурсивно все архивные файлы разнообразных форматов архива и ищите их шаблоны имени файла

Строки, добавленные автоматической функцией конфигурирования, отмечены в Вашем ~/.zshrc:

# Lines configured by zsh-newuser-install
…
# End of lines configured by zsh-newuser-install

Пока Вы не редактируете эти строки или что-либо промежуточное, можно продолжать использовать интерфейс конфигурирования, и это отредактирует строки между этими маркерами. Добавьте, что Вы хотите прежде или после маркеров. Обычно Вы будете хотеть, чтобы Ваш материал следовал за маркером конца, так, чтобы он не был переопределен настройками от интерфейса конфигурирования.

11
09.08.2012, 02:38
6 ответов

(Адаптированный от того, Как делают меня рекурсивно grep через сжатые архивы?)

Установите 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'\') применяет КОД к каждому соответствию ШАБЛОНА. Название подобранного файла находится в $REPLY. Установка reply массив превращает соответствие в список имен.
  • $REPLY\# представление каталога архива.
  • $REPLY\#/**/*vacation*.jpg соответствия *vacation*.jpg файлы в архиве.
  • N спецификатор шарика заставляет шаблон расшириться до пустого списка, если там не идет ни в какое сравнение.
9
27.01.2020, 19:57

Если Вы хотите что-то более простое, что решение AVFS, я записал, что сценарий Python, чтобы сделать это назвал arkfind. Можно на самом деле просто сделать

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

Это сделает это рекурсивно, таким образом, можно будет посмотреть на архивы в архивах к произвольной глубине.

9
27.01.2020, 19:57
  • 1
    Спасибо, хороший вклад! Особенно, если AVFS не является никакой опцией. –  mdo 05.07.2013, 10:39
  • 2
    Было бы замечательно, если это поддерживает файлы банки. –  Chemik 09.10.2013, 13:52
  • 3
    @Chemik - отмеченный! Я сделаю немного больше работы над ним в эти выходные :) JAR не должен быть слишком твердым, я полагаю, что это - действительно просто zip-файл к внешнему миру. –  detly 09.10.2013, 14:11
  • 4
    @Chemik - Я просто попробовал его, и это должно поддерживать файлы JAR в своей текущей форме так или иначе. Можно ли проверить его, и если это не работает, как Вы ожидаете, регистрируете ошибку на странице Github? (Я действительно просто исправлял ошибку, так, несомненно, обновил бы Вашу копию.) –  detly 12.10.2013, 05:10
  • 5
    Да я вижу теперь, это работает. Можно добавить "файлы JAR" к README :) –  Chemik 12.10.2013, 14:45

Мое обычное решение:

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 здесь используется дважды, поэтому вы можете использовать переменную.

С find вы можете использовать ПУТЬ / К / ПОИСК

2
27.01.2020, 19:57

Другое решение, которое работает - zgrep

zgrep -r filename *.zip
2
27.01.2020, 19:57

ИМХО удобство для пользователя должно быть частью 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

и tar (этот не тестировался. ..)

 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
2
27.01.2020, 19:57

libarchive 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 / zsh , bsdtar не заботится о расширении (например, он не полагается на расширение для определения типа файла).

Обратите внимание, что * vacation * .jpg выше соответствует полному пути к члену архива, а не только имени файла, поэтому он будет совпадать с vacation.jpg , но также и с отпуск / 2014 / file.jpg .

Чтобы сопоставить только имя файла, можно использовать режим extract , использовать -s (подстановка), который использует регулярные выражения с p флаг, чтобы напечатать имена совпадающих файлов, а затем убедиться, что файл не извлечен, например:

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

Обратите внимание, что он выводит список на stderr и добавляет >> в каждую строку. В любом случае bsdtar , как и большинство реализаций tar , может искажать имена файлов на дисплее, если они содержат некоторые символы, такие как новая строка или обратная косая черта (отображаемые как \ n или \ ).

0
27.01.2020, 19:57

Теги

Похожие вопросы