递归循环遍历目录并对目录中的文件运行命令

递归循环遍历目录并对目录中的文件运行命令

我正在尝试反编译某个目录中包含的所有 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在 的子目录中创建输出文件 。例如,如果文件包含来自 包 的类,则输出文件将名为。srctree/a/b/c.classca.bsrc/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 将不会执行反编译。

相关内容