親ディレクトリと子ディレクトリの名前が同じ場合は、ファイルを親ディレクトリに移動します。

親ディレクトリと子ディレクトリの名前が同じ場合は、ファイルを親ディレクトリに移動します。

同じ名前のサブディレクトリをディレクトリから取得し、サブディレクトリ内のすべてのファイルを親ディレクトリに移動する方法が必要です。したがって、次の方法を使用して空のディレクトリをすべて削除/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修飾子を使用した再帰的globbing
  • N:nullglob:一致するものがなくても文句を言わないでください。
  • D:dotglob:隠しファイルを含みます。
  • od:順次深さ優先(葉が自分のいる枝より先に来る)
  • oN: それ以外の場合は、ファイルのリストを並べ替えることを気にしないでください。
  • /:ディレクトリタイプファイルに制限されます。
  • e['expression']expressionコードがtrueを返すファイルを制限します(現在のファイルパスが保存されている場所$REPLY)。
  • $REPLY:t:ファイルの尾(デフォルト名)
  • $REPLY:h:t:ファイルヘッダーの終わり(ディレクトリ名))

bash4.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

findGNU v4.8.0とBash v5.1.8に基づいて試してみてください。

パート1:ディレクトリツリーの解析+重複したサブディレクトリ名の検出

ツリーのディレクトリ構造が次のと仮定します。

./
|__test1/
     |__dirname with space
     |           |__test2
     |                |__ test2
     |__dirname **
     |       |__test1
     |
     |__reboot
     |     |__test1
     | 
     |__test2/
          |__test3/
               |__test2/
                    |__test1/
                         |__test1/

(奇妙なディレクトリ名はコードセキュリティのためです)

一部のサブディレクトリ(サブディレクトリ)が異なる方法で繰り返されることがわかります。一部は、1回ではなく複数回繰り返す(例:)、test1test3)、親ディレクトリとサブディレクトリで繰り返すことも、複数の中間サブディレクトリに分割することもできます。

以下のコードは、ディレクトリ構造のサブディレクトリ名のなりすましを詳細に示しています。

  • ファイルツリーを解析して、次から始まるサブディレクトリ構造を取得します。$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)はこれに依存します。

関連情報