UNIX シェル スクリプト: ファイルを 1 つ上のディレクトリに再帰的に移動するにはどうすればよいですか?

UNIX シェル スクリプト: ファイルを 1 つ上のディレクトリに再帰的に移動するにはどうすればよいですか?

多数の小さなファイル f が次のようなディレクトリ構造に配置されています。

/A/B/C/f

A レベルには 11 個のディレクトリがあり、それぞれに B レベルに約 100 個のディレクトリがあり、それぞれに C レベルに約 30 個のディレクトリがあり、それぞれに 1 つのファイル f があります。

すべてのファイルを 1 レベル上に移動するにはどうすればよいですか? たとえば、次のファイル セットがあるとします...

/A/B/C/f1
/A/B/C/f2
/A/B/C/f3
/A/B/C/f4

ディレクトリに/A/B/f1 から f4 までの 4 つのファイルを含めるようにします。ディレクトリ C を削除する必要はありません。

findこれは、、およびxargsが関係する可能性のある解決済みの問題であることを願っていますwhatnot。何かアイデアはありますか?

乾杯、

ジェームズ

答え1

これは、GNU find (Linux にあるもの) または以下をサポートするその他の find を使用すると非常に簡単です-execdir

find A -type f -execdir mv -i {} .. \;

標準の場合find

find A -type f -exec sh -c 'mv -i "$1" "${1%/*}/.."' sh {} \;

zshの場合:

zmv -Q -o-i 'A/(**/)*/(*)(.)' 'A/$1$2'

ディレクトリ構造のネスト レベルが常に同じである場合は、再帰的なトラバーサルは必要ありません (ただし、最初に空のディレクトリを削除します)。

for x in */*; do; echo mv -i "$x"/*/* "$x"/..; done

答え2

そのファイルセットの場合、次のようにします。

$ cd /A/B/C/
$ mv ./* ../

しかし、あなたの問題はもう少し複雑だと予想しています...これには答えられません...ディレクトリ構造がどうなっているのかよくわかりません...説明していただけますか?

答え3

私の最初の推測は

$ find A -type f -exec mv {} .. \;  

指定しない限りは-depth問題ないはずです。私は試したことがないので、コミットする前にまずテストしてください。

答え4

リーフ ディレクトリにあるファイルのみを移動したい場合 (つまり、サブディレクトリが含まれている場合は/A/B/file移動したくない場合)、それを実行するには次の方法があります。/AB

どちらもこれが必要です

leaf ()
{
    find $1 -depth -type d | sed 'h; :b; $b; N; /^\(.*\)\/.*\n\1$/ { g; bb }; $ {x; b}; P; D'
}
shopt -s nullglob

これは機能します:

leaf A | while read -r dir
do
    for file in "$dir"/*
    do
        parent=${dir%/*}
        if [[ -e "$parent/${file##*/}" ]]
        then
            echo "not moved: $file"
        else
            mv "$file" "$parent"
        fi
    done
done

これはより高速になりますが、空のソース ディレクトリは好ましくありません。

leaf A | while read -r dir
do
    mv -n "${dir}"/* "${dir%/*}"
    remains=$(echo "$dir"/*)
    [[ -n "$remains" ]] && echo "not moved: $remains"
done

関連情報