我正在尝试反编译某个目录中包含的所有 Java 类,从目录顶部开始。
该目录有许多子目录,每个子目录的深度不同。
我要做的是进入每个目录,如果内容是带有后缀的文件.class
,则运行反编译器命令,它将在同一目录中创建一个反编译文件。
我尝试了以下方法,但它们并没有达到我的要求。
第一种方法是:
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
可以调整其中一个来实现我想要的吗?如何将第一个命令转换为递归操作?
答案1
我并不完全清楚 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
。解决此类问题的关键是要明白,你不是第一个想要将命令行输出输出到另一个目标的人。
答案2
jad 支持这个内置功能,根据文件。它将为您扩展 glob,包括**
递归 glob。因此,请使用引号来保护它们免受 shell 的攻击,例如从文档中复制的此示例 cmd:
jad -o -r -sjava -dsrc 'tree/**/*.class'
此命令将反编译位于 的所有子目录中的所有 .class 文件,并根据类的包名称
tree
在 的子目录中创建输出文件 。例如,如果文件包含来自 包 的类,则输出文件将名为。src
tree/a/b/c.class
c
a.b
src/a/b/c.java
如果您喜欢它的目录结构选择,这几乎肯定是最佳选择。看起来没有-r
它就不会将包结构转换为目录。我不知道您是否可以让它将文件放在具有目录结构的文件.java
旁边。.class
find -execdir
在正确的目录中运行jad:
# untested
find [more find options] -name '*.class' -execdir jad {} +
这将有效地cd
对每个包含至少一个的目录执行在那里.class
运行的操作jad *.class
。(请注意,+
而不是\;
将多个参数分组为一个命令)。
GNUfind
功能强大;阅读手册页。
或者使用 bash 功能:
由于您使用的是 bash,因此可以for dir in ./*
使用 bash 的 globstar 功能进行递归。它比find
大目录树慢得多,因为 bash 不知道利用返回的文件类型提示来readdir
避免必须lstat
检查每个目录条目是否是目录。但 bash 递归 glob 可能很有用。
# 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
请注意使用尾随斜杠来使 glob 仅匹配目录。
答案3
我想出了一个对我有用的解决方案:
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 将不会执行反编译。