web-dev-qa-db-ja.com

ディレクトリを再帰的にループし、ディレクトリ内のファイルに対してコマンドを実行します

特定のディレクトリに含まれるすべてのJavaクラスを、ディレクトリの先頭から逆コンパイルしようとしています。

ディレクトリには多くのサブディレクトリがあり、それぞれの深さが異なります。

私がやりたいのは、各ディレクトリに移動し、コンテンツがサフィックス.classのファイルである場合、decompilerコマンドを実行すると、同じディレクトリに逆コンパイルされたファイルが作成されます。

私は次のことを試しましたが、彼らは私が求めているものを達成していません。

最初の方法は次のとおりです。

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

ここでの問題は、再帰的ではないということです。たぶん、これは再帰的になるように微調整することができますか?

2番目の方法ははるかに単純でしたが、最上位ディレクトリにファイルを出力します。これは問題ないかもしれませんが、残念ながら、同じ名前のクラスがありますが、パッケージが異なるため、このソリューションも機能しません。

find . -type f -name "*.class" | while read filename; do echo $filename; done

これらの1つを微調整して、私が望むものを実現できますか?最初のコマンドを再帰操作に変換するにはどうすればよいですか?

6
Mars

私は自分に合った解決策を考え出しました。

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

ファイルがクラスファイルでない場合、jadは逆コンパイルを実行しないため、正しいタイプのファイルをチェックするためにifステートメントは必要ありません。

0
Mars

私はJADが正確にどのように機能するかについて100%しっかりしているわけではありませんが、 このREADME file で見つけた情報に基づいて、この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。このような問題を解決するための鍵は、コマンドライン出力を別の宛先に出力したいと思ったのはあなたが最初ではないことを理解することです。

3
JakeGould

jadはこの組み込みドキュメントによる をサポートしています。 **再帰グロブを含むグロブを拡張します。したがって、ドキュメントからコピーされた次の例のcmdのように、引用符を使用してシェルから保護します。

jad -o -r -sjava -dsrc 'tree/**/*.class'

このコマンドは、treeのすべてのサブディレクトリにあるすべての.classファイルを逆コンパイルし、クラスのパッケージ名に従ってsrcのサブディレクトリに出力ファイルを作成します。たとえば、ファイルtree/a/b/c.classにパッケージa.bのクラスcが含まれている場合、出力ファイルの名前はsrc/a/b/c.Javaになります。

ディレクトリ構造の選択が好きな場合、これはほぼ間違いなく最良のオプションです。 -rがないと、パッケージ構造がディレクトリに変換されないようです。 IDKは、ディレクトリ構造を使用して.Javaファイルの隣に.classファイルを配置できるかどうかを確認します。


find -execdirを使用して正しいディレクトリでjadを実行する

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

これにより、少なくとも1つの.classを含むすべてのディレクトリに効果的にcdが実行され、そこでjad *.classを実行するのと同じことが行われます。 (複数の引数を1つのコマンドにグループ化するには、+ではなく\;に注意してください)。

GNU findは強力です。 manページ を読んでください。


またはbash機能を使用する

Bashを使用しているので、bashのglobstar機能を使用してfor dir in ./*を再帰的にすることができます。大きなディレクトリツリーの場合はfindよりも大幅に遅くなります。これは、bashがreaddirによって返されるファイルタイプのヒントを利用して、毎回lstatする必要がないためです。それがディレクトリであるかどうかを確認するためのdirエントリ。しかし、bashの再帰的なグロブは便利です。

# 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をディレクトリのみに一致させることに注意してください。

1
Peter Cordes