Гаразд, застосуємо філософію 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Глоб класифікатор робить шаблон розширення порожній список , якщо збігу немає.