Хорошо, давайте применим философию 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'\')применяет код для каждого совпадения PATTERN. Имя соответствующего файла находится в $REPLY. Установка replyмассива превращает совпадение в список имен.
$REPLY\# это каталог просмотра архива.
$REPLY\#/**/*.pm Спички .pm файлы в архиве.
- Спецификатор
Nglob расширяет шаблон до пустого списка, если совпадений нет.