6

Я пытаюсь декомпилировать все классы Java, содержащиеся в определенном каталоге, начиная с верхней части каталога.

В каталоге много подкаталогов, и глубина каждого из них различна.

Что я хочу сделать, так это перейти в каждый каталог и, если содержимое представляет собой файл с суффиксом .class , выполнить команду decompiler, которая создаст декомпилированный файл в том же каталоге.

Я попробовал следующее, но они не достигают того, что я хочу.

Первый метод был:

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

Может ли один из них быть настроен для достижения того, что я хочу? Как преобразовать первую команду в рекурсивную операцию?

3 ответа3

3

Я не уверен на 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 . Ключом к решению подобных проблем является понимание того, что вы не первый человек, который хотел вывести выходные данные командной строки в другое место назначения.

1

JAD имеет поддержку для этого встроенного, в соответствии с документацией. Он расширит ваши глобусы, включая ** рекурсивные глобусы. Так что используйте кавычки, чтобы защитить их от оболочки, как, например, этот пример, скопированный из документации:

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, чтобы увидеть, является ли она каталогом. Но рекурсивные шары 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

Обратите внимание на использование конечной косой черты, чтобы глобальные совпадения совпадали только с каталогами.

0

Я пришел к решению, которое сработало для меня:

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 не будет выполнять декомпиляцию, если файл не является файлом класса.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .