
Estou tentando descompilar todas as classes Java contidas em um determinado diretório, começando no topo do diretório.
O diretório possui muitos subdiretórios e a profundidade de cada um é diferente.
O que eu quero fazer é entrar em cada diretório e se o conteúdo for um arquivo com suffix .class
, executar o comando decompiler, que criará um arquivo descompilado no mesmo diretório.
Eu tentei o seguinte, mas eles não alcançaram o que procuro.
O primeiro método foi:
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
O problema aqui é que não é recursivo. Talvez isso possa ser ajustado de uma forma que seja recursivo?
O segundo método era muito mais simples, mas gera os arquivos no diretório superior. Embora isso possa estar ok, infelizmente, tenho classes que têm os mesmos nomes, mas em pacotes diferentes, então esta solução também não funciona:
find . -type f -name "*.class" | while read filename; do echo $filename; done
Um deles pode ser ajustado para alcançar o que desejo? Como o primeiro comando pode ser convertido em uma operação recursiva?
Responder1
Não estou 100% certo sobre como o JAD funciona exatamente, mas com base emas informações que encontrei neste arquivo README, este find
comando deve lhe dar um começo:
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
A -s
opção definirá a extensão de saída como .java
e -d
definirá um diretório de destino para a saída do arquivo com base em onde o .class
arquivo original foi encontrado via find
. A chave para resolver problemas como esse é entender que você não é a primeira pessoa que deseja enviar a saída da linha de comando para outro destino.
Responder2
jad tem suporte para este built-in,de acordo com a documentação. Ele expandirá globs para você, incluindo **
globs recursivos. Portanto, use aspas para protegê-los do shell, como este exemplo cmd copiado dos documentos:
jad -o -r -sjava -dsrc 'tree/**/*.class'
Este comando descompila todos os arquivos .class localizados em todos os subdiretórios
tree
e cria arquivos de saída em subdiretóriossrc
de acordo com os nomes dos pacotes das classes. Por exemplo, se o arquivotree/a/b/c.class
contiver a classec
do pacotea.b
, o arquivo de saída terá um nomesrc/a/b/c.java
.
Esta é quase certamente a melhor opção se você gosta das opções de estrutura de diretórios. Parece que sem -r
ele não transformará a estrutura do pacote em diretórios. IDK se você conseguir colocar os .java
arquivos próximos aos .class
arquivos com sua estrutura de diretórios.
Usando find -execdir
para executar o jad no diretório correto:
# untested
find [more find options] -name '*.class' -execdir jad {} +
Isso irá efetivamente cd
para todos os diretórios que contenham pelo menos um .class
e fará o equivalente a executar jad *.class
lá. (Observe o +
em vez de \;
agrupar vários argumentos em um comando).
GNU find
é poderoso; lera página de manual.
Ou use recursos do bash:
Como você está usando o bash, você pode tornar for dir in ./*
recursivo com o recurso globstar do bash. É significativamente mais lento do que find
grandes árvores de diretórios, porque o bash não sabe aproveitar a dica de tipo de arquivo retornada por readdir
para evitar a necessidade de lstat
cada entrada de diretório para ver se é um diretório. Mas bash globs recursivos podem ser úteis.
# 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
Observe o uso de uma barra final para fazer o glob corresponder apenas aos diretórios.
Responder3
Eu encontrei uma solução que funcionou para mim:
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
Nenhuma if
instrução é necessária para verificar o tipo correto de arquivo porque jad não executará a descompilação se o arquivo não for um arquivo de classe.