Rekursives Durchlaufen von Verzeichnissen und Ausführen eines Befehls für eine Datei im Verzeichnis

Rekursives Durchlaufen von Verzeichnissen und Ausführen eines Befehls für eine Datei im Verzeichnis

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 findBefehl 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 -sOption legt die Ausgabeerweiterung auf fest .javaund -dlegt ein Zielverzeichnis für die Dateiausgabe fest, basierend darauf, wo die Originaldatei .classgefunden 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 treeund erstellt Ausgabedateien in Unterverzeichnissen von srcentsprechend den Paketnamen der Klassen. Wenn die Datei beispielsweise eine Klasse aus dem Paket tree/a/b/c.classenthält , hat die Ausgabedatei den Namen .ca.bsrc/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 -rabzulegen ..java.class


So find -execdirführen Sie jad im richtigen Verzeichnis aus:

# untested
find [more find options]  -name '*.class' -execdir jad {} +

Dies wird effektiv cdin jedes Verzeichnis ausgeführt, das mindestens ein enthält .class, und führt das Äquivalent der Ausführung jad *.classdort aus. (Beachten Sie das +anstelle von \;, um mehrere Argumente in einem Befehl zu gruppieren.)

GNU findist 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 findbei großen Verzeichnisbäumen, da Bash den von zurückgegebenen Dateityphinweis nicht nutzen kann, readdirum zu vermeiden, dass bei lstatjedem 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 ifAnweisung 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.

verwandte Informationen