ネストされたディレクトリのフラット化


71

これはおそらく非常に簡単ですが、私にはわかりません。私はこのようなディレクトリ構造を持っています(dir2はdir1の中にあります):

/dir1
    /dir2 
       |
        --- file1
       |
        --- file2

dir2ではなくdir1でfile1とfile2を取得するような方法で、このディレクタ構造を「フラット化」する最良の方法は何ですか。


回答:


75

GNU findとGNUでこれを行うことができますmv

find /dir1 -mindepth 2 -type f -exec mv -t /dir1 -i '{}' +

基本的に、それfindがディレクトリツリー全体を通過-type fし、最上位ディレクトリにない各ファイル()に対して機能する方法()を-mindepth 2実行して、mv目的のディレクトリに移動します(-exec mv … +)。の-t引数をmv使用すると、最初に宛先ディレクトリを指定できます。これは、の+形式で-execコマンドの最後にすべてのソースの場所を配置するために必要です。-i作るには、mv任意の重複を上書きする前に尋ねます。確認-fせずに上書きする(または確認-nしない、または上書きしない)こともできます。

Stephane Chazelasが指摘しているように、上記はGNUツール(Linuxでは標準ですが、他のほとんどのシステムでは使用できません)でのみ動作します。以下は多少遅くなります(mv複数回呼び出されるため)が、はるかに普遍的です:

find /dir1 -mindepth 2 -type f -exec mv -i '{}' /dir1 ';'

3
-exec +のプロセスを大量に実行しないように編集されましたmv
Random832

1
@ Random832そして、+が機能しないため、再び元に戻ります。mv最終引数として宛先を必要としますが、+は最終引数としてソースを持ちます。あなたがそれを()に変更した構文さえ受け入れないでしょうfind: missing argument to `-exec'
-derobert

1
@ Random832しかし、私は考えmvている-t私たちが使用することができますが、私はそれにそれを変更します。
-derobert

1
@Dom findは、デフォルトで非表示(ドット)ファイルを印刷します。深さは、検索に渡すディレクトリに関連しています。
デロバート

1
または、find ./dir -mindepth 2 -type f -exec mv -f '{}' ./dir ';'もし重複を上書きする
Atav32

33

zshの場合:

mv dir1/*/**/*(.D) dir1

**/サブディレクトリを再帰的に走査します。グロブ修飾子は、 .のみ通常のファイルと一致し、D(名前がで始まるデフォルトでは、ファイルのドットファイルが含まれていることを保証し.、ワイルドカード一致するから除外されています)。後で空のディレクトリをクリーンアップするには、実行しますrmdir dir1/**/*(/Dod)/ディレクトリに制限し、before odを削除するために、最初に一致する深さを順序付けます。dir1/dir2/dir3dir1/dir2

ファイル名の合計の長さが非常に大きい場合、コマンドラインの長さに制限が生じる可能性があります。Zshには、この制限の影響を受けることのないビルトインがmvあり、それらを有効にするためにrmdir実行さzmodload zsh/filesれます。

POSIXツールのみの場合:

find dir1 -type f -exec mv {} dir1 \;
find dir1 -depth -exec rmdir {} \;

または(ファイルごとに個別のプロセスを実行する必要がないため、より高速です)

find dir1 -type f -exec sh -c 'mv "$@" dir1' _ {} +
find dir1 -depth -exec rmdir {} +

1
これは受け入れられた答えであるはずです!特に簡潔なzshバージョンでは。
アダムスキー

3

これを試してみてください:

cp /dir1/dir2/file{1,2} /another/place

またはfile[0-9]*subdirで一致する各ファイルに対して:

cp /dir1/dir2/file[0-9]* /another/place

http://mywiki.wooledge.org/globをご覧ください


これを示すべきでしたが{}、実際の問題で使用する多くのファイルが必要です。
カメ

私の第二の溶液を参照してください
ジルQuenot

ビンゴ。助けてくれてありがとう。これは間違いなく最高のソリューションです。
カメ

2

一緒に使用できる2つの関数を作成しました。これらの関数は、-maxdepth $VALパラメーターを追加することでディレクトリレベルを制限できます。

# This scripts flattens the file directory
# Run this script with a folder as parameter:
# $ path/to/script path/to/folder

#!/bin/bash

rmEmptyDirs(){
    local DIR="$1"
    for dir in "$DIR"/*/
    do
        [ -d "${dir}" ] || continue # if not a directory, skip
        dir=${dir%*/}
        if [ "$(ls -A "$dir")" ]; then
            rmEmptyDirs "$dir"
        else
            rmdir "$dir"
        fi
    done
    if [ "$(ls -A "$DIR")" ]; then
        rmEmptyDirs "$DIR"
    fi
}

flattenDir(){
    local DIR="$1"
    find "$DIR" -mindepth 2 -type f -exec mv -i '{}' "$DIR" ';'
}

read -p "Do you wish to flatten folder: ${1}? " -n 1 -r
echo    # (optional) move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]
then
    flattenDir "$1" &
    rmEmptyDirs "$1" &
    echo "Done";
fi

男、私はパス引数を忘れてスクリプトを誤用しました。[OK]を、私はペーストのものをコピーして、それらを誤用男が、男は、賢明なことだとそのような原料を移動/削除スクリプトのチェック/確認を追加...
dulgan

おっと!それを聞いてすみません。バックアップがあることを願っています...今後の保護のために確認を追加しました。
ブルーノ

@Brunoに感謝します。私のサーバーはまだ完璧に動作しています。スクリプトの実行を停止させるエラーが表示されるまで、ルートから空のディレクトリを再帰的に削除するために「フラット化」部分をコメントしました。
ダルガン

1

同じ名前のファイルを含むディレクトリをフラット化するためのユースケースがあったので、この質問に対する一般的な答えを拡張します。

dir1/
├── dir2
   └── file
└── dir3
    └── file

この場合、に渡される-i--interactive)オプションはmv、ディレクトリ構造を平坦化し、名前の競合を処理するための望ましい結果をもたらしません。そのため、単に--backup=t(に相当--backup=numbered)に置き換えられます。https://www.gnu.org/software/coreutils/manual/coreutils.html#Backup-optionsで利用可能な-b--backup)オプションの詳細なドキュメント。

その結果:

find dir1/ -mindepth 2 -type f -exec mv -t dir1/ --backup=t '{}' +

どちらが得られますか:

dir1/
├── dir2
├── dir3
├── file
└── file.~1~

1

tarとzipの両方にディレクトリ構造を組み込み、それから削除する機能があるため、ネストされたディレクトリをすばやくフラット化できました

tar -cvf all.tar *

その後、all.tarを新しい場所に移動してから

tar -xvf all.tar --strip=4

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.