
Я пытаюсь декомпилировать все классы Java, содержащиеся в определенном каталоге, начиная с верхней части каталога.
Каталог имеет множество подкаталогов, глубина которых различна.
Мне нужно зайти в каждый каталог и, если содержимое представляет собой файл с суффиксом .class
, запустить команду декомпилятора, которая создаст декомпилированный файл в том же каталоге.
Я пробовал следующие варианты, но они не дали мне желаемого результата.
Первый метод был таким:
for dir in ./*; do ( ( if [[ -d $dir ]]; then cd "$dir"; fi ) && ( for f in "$dir"; do ( if [[ -f $f && $f == *".class"* ]]; then jad "$f"; fi ); done ) ); done
Проблема в том, что это не рекурсивно. Может быть, это можно подправить так, чтобы это было рекурсивно?
Второй метод был намного проще, но он выводит файлы в верхнем каталоге. Хотя это может быть нормально, к сожалению, у меня есть классы с одинаковыми именами, но в разных пакетах, поэтому это решение тоже не работает:
find . -type f -name "*.class" | while read filename; do echo $filename; done
Можно ли настроить один из них так, чтобы он соответствовал моим требованиям? Как можно преобразовать первую команду в рекурсивную операцию?
решение1
Я не уверен на 100% в том, как именно работает JAD, но основываясь наинформация, которую я нашел в этом файле README, эта find
команда должна вам помочь начать:
find . -type f -name '*.class' |\
while IFS= read -r java_class_path
do
java_dirname=$(dirname "${java_class_path}")
jad -sjava -d"${java_dirname}" "${java_class_path}"
done
Параметр -s
установит выходное расширение на .java
и задаст целевой каталог для выходного файла на основе того, где был найден -d
исходный файл через . Ключ к решению таких проблем — понимать, что вы не первый человек, который захотел вывести вывод командной строки в другое место назначения..class
find
решение2
jad имеет встроенную поддержку для этого,согласно документации. Он расширит для вас globs, включая **
рекурсивные globs. Поэтому используйте кавычки, чтобы защитить их от оболочки, как в этом примере cmd, скопированном из документации:
jad -o -r -sjava -dsrc 'tree/**/*.class'
Эта команда декомпилирует все файлы .class, расположенные во всех подкаталогах
tree
и создает выходные файлы в подкаталогахsrc
в соответствии с именами пакетов классов. Например, если файлtree/a/b/c.class
содержит классc
из пакетаa.b
, то выходной файл будет иметь имяsrc/a/b/c.java
.
Это почти наверняка лучший вариант, если вам нравится его выбор структуры каталогов. Мне кажется, что без -r
него структура пакетов не будет преобразована в каталоги. IDK, если вы могли бы заставить его размещать .java
файлы рядом с файлами .class
с вашей структурой каталогов.
Использование find -execdir
для запуска jad в правильном каталоге:
# untested
find [more find options] -name '*.class' -execdir jad {} +
Это фактически перейдет cd
к каждому каталогу, содержащему хотя бы один .class
, и выполнит эквивалент запуска jad *.class
там. (Обратите внимание на использование +
вместо , \;
чтобы сгруппировать несколько аргументов в одну команду).
GNU find
— мощный инструмент; читайтестраница руководства.
Или используйте возможности bash:
Поскольку вы используете bash, вы можете сделать for dir in ./*
рекурсивный с помощью функции bash globstar. Это значительно медленнее, чем find
для больших деревьев каталогов, потому что bash не знает, что нужно использовать подсказку о типе файла, возвращаемую , readdir
чтобы избежать необходимости lstat
проверять каждую запись dir, является ли это каталогом. Но рекурсивные globs bash могут быть полезны.
# untested
shopt -s globstar # put this in your .bashrc if you want it enabled all the time
for dir in ./**/; do
pushd "$dir"
classfiles=( *.class ) # expand the glob into an array
[[ -e $classfiles ]] && # test the first element of the array. Will fail if *.class didn't match anything.
jad *.class
popd "$dir"
done
Обратите внимание на использование завершающего слеша, чтобы глобальный шаблон соответствовал только каталогам.
решение3
Я нашел решение, которое мне помогло:
find . -type d | while read dir; do ( if [[ -d $dir ]]; then cd $dir && find . -maxdepth 1 -type f | while read f; do ( jad $f ); done fi ); done
if
Для проверки правильности типа файла не требуется никаких инструкций, поскольку jad не будет выполнять декомпиляцию, если файл не является файлом класса.