2 番目のレベルのサブディレクトリで「1 レベル上に」ファイルを移動する

2 番目のレベルのサブディレクトリで「1 レベル上に」ファイルを移動する

デフォルトでは、1..M個のディレクトリ(DIRA-DIRZ)を含む親ディレクトリ(PARENT)があり、各ディレクトリには0..N個のディレクトリ(DIR1-DIRN)が含まれており、各ディレクトリにはファイルリスト(FILEa -FILEz )が含まれています。 。

PARENT/DIRA/DIR1/files
PARENT/DIRB/files
PARENT/DIRC/DIR2/files
PARENT/DIRC/DIR3/files

...セカンダリディレクトリ(DIR1-DIRN)が存在する場合は、ファイルをセカンダリディレクトリ(DIR1)からそれを含むプライマリディレクトリ(DIRA)に移動し、現在空のセカンダリディレクトリ(DIR1)を削除します。

PARENT/DIRA/files
PARENT/DIRB/files
PARENT/DIRC/files

私はこの作品を使用しようとしていることがわかりました。

find /thisdir -type f -name "*.ogg" -exec mv {} /somedir \;

ただし、外部ループとそれを統合する方法を理解することはできません。

提供できる助け、特に説明が役に立ちます!

答え1

ほとんどすべてのLinuxディストリビューション(少なくともメジャーディストリビューション)にはPythonがプリインストールされているため、簡単なPythonスクリプトを書くのは簡単です。

#!/usr/bin/env python3
import sys
from pathlib import Path


def flatten_and_del(targdir):
    pardir = targdir.parent
    for f in targdir.glob("*"):
        f.rename(pardir / f.name)
    targdir.rmdir()


def process_dir(parent):
    parent = Path(parent)
    if not parent.is_dir():
        raise RuntimeError(f"{parent} is not a directory!")
    for f in parent.glob("*"):
        if not f.is_dir():
            continue
        flatten_and_del(f)


if __name__ == "__main__":
    process_dir(sys.argv[1])

たとえば、別の名前で保存し、tidy-dirs.py次のように実行します。

python3 tidy-dirs.py path/to/PARENT

警告する:αГsнιιがコメントで述べたように、このアプローチは〜するファイル名が競合すると、データが失われる可能性があります。これが発生しないようにするには、実行する前に確認をflatten_and_del追加してください。target.exists().rename()

答え2

そしてzsh

autoload zmv # best in ~/.zshrc
zmv '(PARENT)/(*)/*/(*)(#qD)' '$1/$2/$3'
rmdir PARENT/*/*(#qD/^F)

答え3

実際、これは2つのコマンドです。 1つ目はmv親ファイルを削除し、2つ目は空のディレクトリを削除することです。
(2つのコマンドを1つに連結して&&1行のように見せます。)

find -H PARENT -mindepth 3 ! -type d -execdir cp --backup=numbered -al {} .. \; -delete && find -H PARENT -depth -mindepth 2 -type d -exec rmdir {} +

mvハードリンクを作成し、ソースを削除する代わりに。cp内蔵バックアップソリューションを提供する:

cp は、--backup=numbered他のファイルがすでに存在する場合、自動的にファイル名を変更します。
cp-lはコピーする代わりにハードリンクを作成します。
cpは-aメタデータ(mtime、権限)を保持します。
findは-deleteすべてを再帰的に削除します(注意して使用)。

説明されているすべてのfind主張:

-H
PARENTがシンボリックリンクの場合(=反転引数)と同じ項目を見つけます。! -type d*/*/*/ レベル 3 のファイルのみを検索します (より安全にするために使用されます)。サブディレクトリで実行コマンドを探します。-type f!
-mindepth 3-maxdepth 3
-execdir

\;と説明の違い+

CMD ARG1のシリアル1:1実行を見つけます-exec CMD {} \;。 ...(ここでARGはfindの結果です)CMD ARG1 ARG2 ARG3 ... ARGNの並列実行を
探します。-exec CMD {} +


PARENT"$@"端末で実行する代わりに、複数の引数で実行される小さなシェルスクリプトを置き換えて生成することができます。

sh ./myscript.sh PARENT [PARENT2...]スクリプトの実行

#!/bin/sh
test -e "$1" || exit 1
find -H "$@" -mindepth 3 ! -type d -execdir cp --backup=numbered -al {} .. \; -delete
find -H "$@" -depth -mindepth 2 -type d -exec rmdir {} +

答え4

これを行う必要があるディレクトリが多い場合は、単純なbashスクリプトを使用してこの問題を簡単に解決して時間を節約できます。

ディレクトリは1つだけです。

parent/
└── DIRA
    └── DIR1
        ├── file1.ogg
        ├── file2.ogg
        └── file3.ogg

次に、DIR1の内部で次のことを行います。

# You can also use ; over && but the second one is more reliable,
# specially if you are doing this in a remote server.

mv *.ogg ../ && cd ../ && rmdir DIR1/

結果:

parent/
└── DIRA
    ├── file1.ogg
    ├── file2.ogg
    └── file3.ogg

セカンダリディレクトリ内のすべてのファイルが.oggであると確信している場合は、次のものを使用できます。MV*変えるMV*.ogg

関連情報