回答:
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 ';'
-exec +
のプロセスを大量に実行しないように編集されましたmv
mv
最終引数として宛先を必要としますが、+は最終引数としてソースを持ちます。あなたがそれを()に変更した構文さえ受け入れないでしょうfind: missing argument to `-exec'
mv
ている-t
私たちが使用することができますが、私はそれにそれを変更します。
find
は、デフォルトで非表示(ドット)ファイルを印刷します。深さは、検索に渡すディレクトリに関連しています。
find ./dir -mindepth 2 -type f -exec mv -f '{}' ./dir ';'
もし重複を上書きする
zshの場合:
mv dir1/*/**/*(.D) dir1
**/
サブディレクトリを再帰的に走査します。グロブ修飾子は、 .
のみ通常のファイルと一致し、D
(名前がで始まるデフォルトでは、ファイルのドットファイルが含まれていることを保証し.
、ワイルドカード一致するから除外されています)。後で空のディレクトリをクリーンアップするには、実行しますrmdir dir1/**/*(/Dod)
— /
ディレクトリに制限し、before od
を削除するために、最初に一致する深さを順序付けます。dir1/dir2/dir3
dir1/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 {} +
一緒に使用できる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
同じ名前のファイルを含むディレクトリをフラット化するためのユースケースがあったので、この質問に対する一般的な答えを拡張します。
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~