web-dev-qa-db-ja.com

新しいディレクトリ名でディレクトリ名を保持するディレクトリ階層の平坦化

私は基本的にこれから行きたいです:

.
├── Alan Walker
│   ├── Different World
│   │   ├── 01 Intro.mp3
│   │   ├── 02 Lost Control.mp3
│   │   └── cover.jpg
│   └── Same World
│       ├── 01 Intro.mp3
│       └── 02 Found Control.mp3
├── Aurora
│   └── Infections Of A Different Kind Step 1
│       ├── 01 Queendom.lrc
│       ├── 02 Forgotten Love.lrc
│       └── 03 Gentle Earthquakes.mp3
└── Guns N' Roses
    └── Use Your Illusion I
        ├── 01 Right Next Door To Hell.lrc
        ├── 01 Right Next Door To Hell.mp3
        ├── 02 Dust N' Bones.lrc
        └── 02 Dust N' Bones.mp3

これに:

.
├── Alan Walker - Different World
│   ├── 01 Intro.mp3
│   ├── 02 Lost Control.mp3
│   └── cover.jpg
├── Alan Walker - Same World
│   ├── 01 Intro.mp3
│   └── 02 Found Control.mp3
├── Aurora - Infections Of A Different Kind Step 1
│   ├── 01 Queendom.lrc
│   ├── 02 Forgotten Love.lrc
│   └── 03 Gentle Earthquakes.mp3
└── Guns N' Roses - Use Your Illusion I
    ├── 01 Right Next Door To Hell.lrc
    ├── 01 Right Next Door To Hell.mp3
    ├── 02 Dust N' Bones.lrc
    └── 02 Dust N' Bones.mp3

私が見つけた既存の解決策のどれも、ディレクトリ自体の名前を変更することを含みませんでした。これをzmvで実行できると便利ですが、方法がわかりません。

7
aksh1618

Zsh

未テスト:

zmv -Q '(*)/(*)(/)' '$1 - $2'
rmdir -- *(/^F)

2行目は、空のディレクトリをすべて削除します。以前にファイルがなかったディレクトリも削除されます。移動元のディレクトリを記録するカスタムmvラッパーを使用してこれを回避することが可能です。

これは、現在のディレクトリ内のディレクトリへのシンボリックリンクをトラバースすることに注意してください。

Linux名前変更ユーティリティ

未テスト。

rename / ' - ' */*/
rmdir -- */ 2>/dev/null

これは、現在のディレクトリおよびそのサブディレクトリ内のディレクトリへのシンボリックリンクを通過することに注意してください。 2行目は、空のディレクトリをすべて削除します。以前にファイルがなかったディレクトリも削除されます。

Perl名前変更スクリプト

未テスト。

prename 's~/~ - ~' */*/
rmdir -- */ 2>/dev/null

これは、現在のディレクトリおよびそのサブディレクトリ内のディレクトリへのシンボリックリンクを通過することに注意してください。 2行目は、空のディレクトリをすべて削除します。以前にファイルがなかったディレクトリも削除されます。

次に、名前を変更したディレクトリのみを削除する、より複雑な方法を示します。再び、テストされていません。

prename 's~([^/]+)/~$1 - ~ and ++$d{$1}; END {map {rmdir} keys %d}' */*/

このような何か?

#!/bin/sh

for topdir in */; do
    topdir_name=$( basename "$topdir" )

    for subdir in "$topdir"/*/; do
        subdir_name=$( basename "$subdir" )

        newdir="$topdir_name - $subdir_name"
        if mkdir "$newdir"; then
            mv "$subdir"/* "$newdir"
            rmdir "$subdir"
        fi
    done

    rmdir "$topdir"
done

これは、現在のディレクトリ(バンド名)内のすべてのトップレベルディレクトリを通過します。そのようなディレクトリごとに、サブディレクトリ(アルバム名)を通過します。バンド名とアルバム名のペアごとに、新しいディレクトリが作成され、サブディレクトリのファイルがそこに移動されます。アルバムサブディレクトリは、元のバンドのトップレベルディレクトリと同様に、処理されると削除されます。

ディレクトリに隠しファイル名が含まれている場合、または新しいディレクトリのいずれかを作成できなかった場合、rmdir呼び出しは失敗します。

これは完全にテストされていないコードです。ファイルのバックアップコピーで実行します。

12
Kusalananda

戦略的に、ファイルを移動するのではなく、現在の構造をそのままにして、必要な新しい構造へのリンクを作成することを検討しましたか?

戦術的には、この仕事をするパターンは次のようになります。

find . -mindepth 2 -maxdepth 2 -type d -print0 | xargs -0n1 bash -c \
  'b=$(basename "$(dirname "$1")"); a=$(basename "$1"); echo ln -s "$1" "$b-$a"' {}
  • findは、現在の作業ディレクトリから2レベル下のすべてのディレクトリを検索します。これは、バンドを含むディレクトリです。したがって、2レベル下は、バンド名の下のアルバム名です。1
  • xargsは、アルバムを含む各パスを使用し、インラインbashスクリプトを呼び出します。
  • bash -c '...'は、最初の引数としてアルバムパスを受け取り、そのパスを2つの部分に分割します。バンド($b)とアルバム($a)。最後に、スクリプトは名前を目的の形式に再構成し、新しいディレクトリ名を元のディレクトリにリンクします。

この例では、リンクは開始時と同じディレクトリに作成されることに注意してください。これは、バンド名の場所でもあります。

上記のln戦略を調整して、意図に合わせることができます。 mvは、物理的に再配置したい場合は正しいパスを使用し、lnはメディア上で便利な「ビュー」を作成したい場合に使用します。 bashスクリプト内の重要な部分は次のとおりです。

  • $bバンド名。常に引用してください:"$b"
  • $aアルバム名。常に引用してください:"$a"
  • $1アルバムディレクトリへの物理パス。常に引用してください:"$1"

1 私は信じている m{ax,in}depthは、GNUおよび一部のBSD findでサポートされていますが、POSIXではサポートされていません。その場合、*/*または同様のシェル体操。

4
bishop