
Ich versuche, alle Java-Klassen in einem bestimmten Verzeichnis zu dekompilieren, beginnend am Anfang des Verzeichnisses.
Das Verzeichnis verfügt über viele Unterverzeichnisse und die Tiefe jedes einzelnen ist unterschiedlich.
Ich möchte in jedes Verzeichnis gehen und, wenn der Inhalt eine Datei mit der Endung ist .class
, den Decompiler-Befehl ausführen, der eine dekompilierte Datei im selben Verzeichnis erstellt.
Ich habe Folgendes versucht, aber es führt nicht zu meinem Ziel.
Die erste Methode war:
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
Das Problem hierbei ist, dass es nicht rekursiv ist. Vielleicht kann dies so optimiert werden, dass es rekursiv wird?
Die zweite Methode war viel einfacher, gibt aber die Dateien im obersten Verzeichnis aus. Das wäre zwar in Ordnung, aber leider habe ich Klassen mit den gleichen Namen, aber in unterschiedlichen Paketen, sodass diese Lösung auch nicht funktioniert:
find . -type f -name "*.class" | while read filename; do echo $filename; done
Kann einer davon angepasst werden, um das gewünschte Ergebnis zu erzielen? Wie kann der erste Befehl in eine rekursive Operation umgewandelt werden?
Antwort1
Ich bin mir nicht 100% sicher, wie JAD genau funktioniert, aber basierend aufdie Informationen, die ich in dieser README-Datei gefunden habe, dieser find
Befehl sollte Ihnen einen Einstieg ermöglichen:
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
Die -s
Option legt die Ausgabeerweiterung auf fest .java
und -d
legt ein Zielverzeichnis für die Dateiausgabe fest, basierend darauf, wo die Originaldatei .class
gefunden wurde find
. Der Schlüssel zur Lösung solcher Probleme besteht darin, zu verstehen, dass Sie nicht die erste Person sind, die die Befehlszeilenausgabe an ein anderes Ziel ausgeben wollte.
Antwort2
jad hat Unterstützung für diese integrierte,gemäß der Dokumentation. Es wird Globs für Sie erweitern, einschließlich **
rekursiver Globs. Verwenden Sie daher Anführungszeichen, um sie vor der Shell zu schützen, wie in diesem Beispiel-Cmd, das aus den Dokumenten kopiert wurde:
jad -o -r -sjava -dsrc 'tree/**/*.class'
Dieser Befehl dekompiliert alle .class-Dateien in allen Unterverzeichnissen von
tree
und erstellt Ausgabedateien in Unterverzeichnissen vonsrc
entsprechend den Paketnamen der Klassen. Wenn die Datei beispielsweise eine Klasse aus dem Pakettree/a/b/c.class
enthält , hat die Ausgabedatei den Namen .c
a.b
src/a/b/c.java
Dies ist mit ziemlicher Sicherheit die beste Option, wenn Ihnen die Auswahl der Verzeichnisstruktur gefällt. Es sieht so aus, als würde die Paketstruktur ohne sie nicht in Verzeichnisse umgewandelt. Ich weiß nicht, ob Sie es dazu bringen könnten, die Dateien neben den Dateien mit Ihrer Verzeichnisstruktur -r
abzulegen ..java
.class
So find -execdir
führen Sie jad im richtigen Verzeichnis aus:
# untested
find [more find options] -name '*.class' -execdir jad {} +
Dies wird effektiv cd
in jedes Verzeichnis ausgeführt, das mindestens ein enthält .class
, und führt das Äquivalent der Ausführung jad *.class
dort aus. (Beachten Sie das +
anstelle von \;
, um mehrere Argumente in einem Befehl zu gruppieren.)
GNU find
ist leistungsstark; lesen Siedie Manpage.
Oder verwenden Sie Bash-Funktionen:
Da Sie Bash verwenden, können Sie for dir in ./*
mit der Globstar-Funktion von Bash rekursiv arbeiten. Dies ist deutlich langsamer als find
bei großen Verzeichnisbäumen, da Bash den von zurückgegebenen Dateityphinweis nicht nutzen kann, readdir
um zu vermeiden, dass bei lstat
jedem Verzeichniseintrag geprüft werden muss, ob es sich um ein Verzeichnis handelt. Rekursive Bash-Globs können jedoch nützlich sein.
# 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
Beachten Sie die Verwendung eines abschließenden Schrägstrichs, damit der Glob nur Verzeichnisse abgleicht.
Antwort3
Ich habe eine Lösung gefunden, die bei mir funktioniert hat:
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
Es ist keine if
Anweisung erforderlich, um den richtigen Dateityp zu prüfen, da jad die Dekompilierung nicht durchführt, wenn es sich bei der Datei nicht um eine Klassendatei handelt.