同じ名前のサブディレクトリをディレクトリから取得し、サブディレクトリ内のすべてのファイルを親ディレクトリに移動する方法が必要です。したがって、次の方法を使用して空のディレクトリをすべて削除/recup-dir1/recup-dir1/files to /recup-dir1/files.
できるため、サブディレクトリを空白にすることができます。
find . -type -d -empty -delete
だから問題は、どのディレクトリに同じ名前のサブディレクトリがあり、どのディレクトリにないのかわからないということです。
擬似コードにはこのようなものが必要です。
While more directories are unchecked
get name-x of next dir
enter dir
If name-x/name-x exist
move all files in name-x/name-x to name-x
mark dir as done
next
私の推測では、小さなPythonスクリプトを作成して、同じ名前のサブディレクトリを含むすべてのディレクトリのリストを作成し、次のコマンドを使用してこのリストを繰り返すことです。
find something something -exec mv
たぶんこれはbashスクリプトを介して行うことができ、他の解決策が存在するかもしれません。いくつかのrsyncコマンドと似ていますが、rsyncを使用してこの混乱を作成した可能性があるため、これは解決策ではないと思います。
編集:これはツリー出力の実際の部分です。最上位ディレクトリは/mnt/external-disk/tst-backup内にあり、下位レベルには下位ディレクトリはありません。
│ └── recup_dir.1
├── recup_dir.10
│ └── recup_dir.10
├── recup_dir.100
│ └── recup_dir.100
├── recup_dir.102
│ └── recup_dir.102
└── recup_dir.1020
└── recup_dir.1020
答え1
これにより、zsh
次のことができます。
for dir in **/*(NDodoN/e['[[ $REPLY:t = $REPLY:h:t ]]']); do
contents=($dir/*(NDoN))
(( $#contents == 0 )) ||
mv -- $contents $dir:h/ &&
rmdir -- $dir
done
どこ:
**/*(qualifiers)
glob修飾子を使用した再帰的globbingN
:nullglob:一致するものがなくても文句を言わないでください。D
:dotglob:隠しファイルを含みます。od
:順次深さ優先(葉が自分のいる枝より先に来る)oN
: それ以外の場合は、ファイルのリストを並べ替えることを気にしないでください。/
:ディレクトリタイプファイルに制限されます。e['expression']
:expression
コードがtrueを返すファイルを制限します(現在のファイルパスが保存されている場所$REPLY
)。$REPLY:t
:ファイルの尾(デフォルト名)$REPLY:h:t
:ファイルヘッダーの終わり(ディレクトリ名))
bash
4.4+ および GNUfind
またはほとんどの BSD では、find
次のようにできます。
shopt -s nullglob dotglob
readarray -td '' dirs < <(
LC_ALL=C find . -depth -regex '.*\(/[^/]*\)\1' -type d -print0
)
for d in "${dirs[@]}"; do
contents=("$d"/*)
(( ${#contents[@]} == 0 )) ||
mv -- "${contents[@]}" "${d%/*}/" &&
rmdir -- "$d"
done
./path/to/dir/dir
今回は、デフォルトの正規表現を使用して逆参照ファイルを一致させるために正規表現が使用されます。
答え2
find
GNU v4.8.0とBash v5.1.8に基づいて試してみてください。
パート1:ディレクトリツリーの解析+重複したサブディレクトリ名の検出
ツリーのディレクトリ構造が次のと仮定します。
./
|__test1/
|__dirname with space
| |__test2
| |__ test2
|__dirname **
| |__test1
|
|__reboot
| |__test1
|
|__test2/
|__test3/
|__test2/
|__test1/
|__test1/
(奇妙なディレクトリ名はコードセキュリティのためです)
一部のサブディレクトリ(サブディレクトリ)が異なる方法で繰り返されることがわかります。一部は、1回ではなく複数回繰り返す(例:)、test1
(test3
)、親ディレクトリとサブディレクトリで繰り返すことも、複数の中間サブディレクトリに分割することもできます。
以下のコードは、ディレクトリ構造のサブディレクトリ名のなりすましを詳細に示しています。
- ファイルツリーを解析して、次から始まるサブディレクトリ構造を取得します。
$PWD
- ルートレベル()を計算せずに、2つ以上のレベルでサブディレクトリパスのすべてのコンポーネントの重複を見つけます
$PWD
。私の実験では、最長のサブディレクトリパスは次のとおりです。./test1/test2/test1/test3/test2/test1/test1
- リーフから始めて、各サブディレクトリレベルで見つかった最初のサブディレクトリのコピーを印刷します。つまり、サブディレクトリのパスを右から左に読み込みます。
- 印刷時にファイルが逆順にリダイレクトされるため、最長のサブディレクトリパスが最初に表示されます。 2つの連続したセミコロンは、パスコンポーネント(「;;」の左側)を前の箇条書き(「;;」の右側)に基づいて見つかった最初の重複項目と区別します。
[パスワード]
$ find ./* -type d -exec bash -c 'set -o noglob; IFS="/" subdir=($(printf "%s " "$1")); dirlevels=$((${#subdir[@]}-1)); dupe="$(awk '\''!($1 in sd) {sd[$1];next} {print $1}'\'' < <(printf "%s\n" ${subdir[@]:1}))";[ $dirlevels -ge 2 ] && [ ! -z "$dupe" ] && (printf "%s/" "${subdir[@]:1}";printf " ;; %s\n" "$(tail -n 1 < <(printf "%s\n" "$dupe"))";)' shellexec {} \; | tac >| tmp.data
$ cat -n tmp.data
1 test1/reboot/test1/ ;; test1
2 test1/dirname with space/test2/test2/ ;; test2
3 test1/test2/test1/test3/test2/test1/test1/ ;; test1
4 test1/test2/test1/test3/test2/test1/ ;; test1
5 test1/test2/test1/test3/test2/ ;; test2
6 test1/test2/test1/test3/ ;; test1
7 test1/test2/test1/ ;; test1
8 test1/dirname **/test1/ ;; test1
パート2:重複したサブディレクトリ名の処理、コンテンツの移動
処理は、に示されている順序で行われますtmp.data
。
- の最初の行では、
tmp.data
パスの最初のなりすましの名前./test1/test2/test1/test3/test2/test1/test1
ですtest1
。その内容を同じ名前の左端のサブディレクトリに転送できます。./test1/
- ターゲットの既存のファイルを削除せずにコンテンツが移動されると、右端のサブディレクトリレベルが
test1
削除されます。 - 2行目を続けて
tmp.data
上記の手順を繰り返します。 - すべての行が
tmp.data
消費されるまで待ちます。
この段階で、質問(質問者:@TomDerks)は、test1/*
6行目の一番右のコンテンツで何をすべきですか?です。しなければならないみんなその内容は、同じ名前の一番左のディレクトリ(この場合はパスの最初のサブディレクトリレベル)に移動されますか? 「すべて」には次のファイルが含まれていますか?./test1/test2/test1/
またサブディレクトリtest3
とその内容は何ですか?
完全なソリューション(パート2)はこれに依存します。