web-dev-qa-db-ja.com

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/ 4つのファイル、f1からf4を含みます。ディレクトリCを削除する必要はありません。

これが解決された問題であり、おそらくfindxargs、およびwhatnotが関係していることを願っています。何か案は?

乾杯、

ジェームズ

8
jl6

GNU find(Linuxで見られるように)または-execdirをサポートする他のfindを使用すると、かなり簡単です。

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

そのファイルのセットの場合、これは次のようになります。

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

しかし、あなたの問題はもう少し複雑だと思います...これには答えられません...あなたのdir構造がどのようになっているのかよくわかりません...明確にしていただけますか?

1
BloodPhilia

私の最初の推測は

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

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

0
hotei

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

両方ともこれが必要です

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