フォルダ構造のフラット化

フォルダ構造のフラット化

フォルダ構造は次のようになります:

├── foo1
│   ├── bar1.txt
│   └── bar2.txt
├── foo2
│   ├── bar3.txt
│   └── bar4 with a space.txt
└── foo3
    └── qux1
        ├── bar5.txt
        └── bar6.txt

これを次のようにフラット化し、各フォルダー レベルの間にアンダースコアを入れます。

├── foo1_bar1.txt
├── foo1_bar2.txt
├── foo2_bar3.txt
├── foo2_bar4 with a space.txt
├── foo3_qux1.bar6.txt
└── foo3_qux1_bar5.txt

いろいろ調べてみましたが、有効な解決策は見つかりませんでした。主な原因は、問題に 2 つの特殊性があるためだと思います。ルート フォルダー内に複数のフォルダー レベルがある可能性があり、一部のファイルにスペースが含まれている可能性もあります。

これを bash で実現する方法をご存知ですか? ありがとうございます!

編集: gleen jackman の提案した回答を実行すると、次のようになります:

ここに画像の説明を入力してください

最初のレベルのフォルダーには 2 つのアンダースコアがあります。これを回避する方法、またはアンダースコアが 1 つだけになるように名前を変更する方法をご存知ですか? ありがとうございます。

答え1

find */ -type f -exec bash -c 'file=${1#./}; echo mv "$file" "${file//\//_}"' _ '{}' \;

echo動作に問題がなければ削除してください。エコーされたコマンドに引用符が表示されなくても心配する必要はありません。スクリプトはスペースを含むファイルを適切に処理します。

空になったサブディレクトリを削除する場合:

find */ -depth -type d -exec echo rmdir '{}' \; 

答え2

perl の rename を使用する:

find . -depth -type f -exec rename 's@(?<!\.)/@_@g' -- {} \;

出力

$ find -type f
./foo2_bar4 whit a space.txt
./foo3_qux1_bar6.txt
./foo2_bar3.txt
./foo3_qux1_bar5.txt
./foo1_bar2.txt
./foo1_bar1.txt

注記

  • 私は後ろを振り返る (?<!\.)最初に触れないように./
  • 空のディレクトリはそのまま残しておきますので、ご自由にお使いください:

    find . -depth -type d -exec rm {} \;

警告同じ名前の他のツールも存在しますが、これが実行できる場合とできない場合がありますので注意してください。

次のコマンド(GNU)を実行すると

$ file "$(readlink -f "$(type -p rename)")"

そして結果は次のようになります

.../rename: Perl script, ASCII text executable

以下を含まない:

ELF

これは適切なツールのようです =)

Debianそうでない場合は、次のようにして派生をデフォルト (通常は既にデフォルトになっています) にしますUbuntu

$ sudo update-alternatives --set rename /path/to/rename

(コマンド/path/to/renameのパスに置き換えてくださいperl's rename


このコマンドがない場合は、パッケージマネージャーを検索してインストールするか、手動で行う


最後になりましたが、このツールは元々、Perl の父である Larry Wall によって作成されました。

答え3

pax...

pax -Xrwls '|/|_|g' */ "$PWD"

_これにより、が に置き換えられた、現在のディレクトリの子ディレクトリ内のすべてのファイルへのハードリンクが作成されます/。その後、結果を調べて、すべての子ディレクトリを削除できます...

rm -rf */

...結果が満足のいくものであることを確認したら。

答え4

以下のコマンドを試すことができます。

$ find -type f -exec bash -c 'mv $0 $(echo $0|sed "s/\//_/2")' {} \;

上記のコマンドはファイルを移動しますが、ディレクトリは残ります。これは後で削除できます。

$ ls
foo1_bar1.txt  foo1_bar2.txt  foo2_bar3.txt  foo2_bar4.txt  foo3_bar5.txt  foo3_bar6.txt

関連情報