
Estoy intentando descompilar todas las clases de Java contenidas en un directorio determinado, comenzando en la parte superior del directorio.
El directorio tiene muchos subdirectorios y la profundidad de cada uno es diferente.
Lo que quiero hacer es ir a cada directorio y si el contenido es un archivo con sufijo .class
, ejecutar el comando del descompilador, que creará un archivo descompilado en el mismo directorio.
Intenté lo siguiente pero no logran lo que busco.
El primer método fue:
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
El problema aquí es que no es recursivo. ¿Quizás esto pueda modificarse de manera que sea recursivo?
El segundo método fue mucho más simple, pero genera los archivos en el directorio superior. Si bien esto podría estar bien, desafortunadamente tengo clases que tienen los mismos nombres, pero en paquetes diferentes, por lo que esta solución tampoco funciona:
find . -type f -name "*.class" | while read filename; do echo $filename; done
¿Se puede modificar uno de estos para lograr lo que quiero? ¿Cómo se puede convertir el primer comando en una operación recursiva?
Respuesta1
No estoy 100% seguro de cómo funciona JAD exactamente, pero basándome enla información que encontré en este archivo README, este find
comando debería darle un comienzo:
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
La -s
opción establecerá la extensión de salida .java
y -d
establecerá un directorio de destino para la salida del archivo según dónde .class
se encontró el archivo original a través de find
. La clave para resolver problemas como este es comprender que no es la primera persona que desea enviar la salida de la línea de comando a otro destino.
Respuesta2
jad tiene soporte para esto incorporado,según la documentación. Expandirá los globos por usted, incluidos **
los globos recursivos. Así que use comillas para protegerlos del shell, como este ejemplo cmd copiado de los documentos:
jad -o -r -sjava -dsrc 'tree/**/*.class'
Este comando descompila todos los archivos .class ubicados en todos los subdirectorios de
tree
y crea archivos de salida en los subdirectoriossrc
de acuerdo con los nombres de los paquetes de las clases. Por ejemplo, si el archivotree/a/b/c.class
contiene una clasec
del paquetea.b
, entonces el archivo de salida tendrá un nombresrc/a/b/c.java
.
Es casi seguro que esta es la mejor opción si le gustan las opciones de estructura de directorios. Parece que sin -r
él no se convertirá la estructura del paquete en directorios. IDK si pudiera lograr que coloque los .java
archivos al lado de los .class
archivos con su estructura de directorios.
Usando find -execdir
para ejecutar jad en el directorio correcto:
# untested
find [more find options] -name '*.class' -execdir jad {} +
Esto afectará efectivamente cd
a cada directorio que contenga al menos un archivo .class
, y hará el equivalente a ejecutarlo jad *.class
allí. (Tenga en cuenta que +
en lugar de \;
agrupar varios argumentos en un solo comando).
GNU find
es poderoso; leerla página de manual.
O usar funciones de bash:
Como estás usando bash, puedes hacerlo for dir in ./*
recursivo con la función globstar de bash. Es significativamente más lento que find
para árboles de directorios grandes, porque bash no sabe aprovechar la sugerencia de tipo de archivo devuelta readdir
para evitar tener que revisar lstat
cada entrada del directorio para ver si es un directorio. Pero los globos recursivos de bash pueden resultar útiles.
# 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
Tenga en cuenta el uso de una barra diagonal para que el globo coincida solo con directorios.
Respuesta3
Se me ocurrió una solución que funcionó para mí:
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
No if
es necesaria ninguna declaración para verificar el tipo correcto de archivo porque jad no realizará la descompilación si el archivo no es un archivo de clase.