ファイルをサブディレクトリから現在のレベルに移動し、ファイルが存在する場合は名前を変更します。

ファイルをサブディレクトリから現在のレベルに移動し、ファイルが存在する場合は名前を変更します。

私はMacを使用しているので、mvは少し異なり、その--backupプロパティをサポートしていません。私が思いつく最善の方法は次のとおりです。

find . -mindepth 2 -type f -print -exec mv {} . \;     

答え1

いくつかのスクリプトを書く必要があります。それは次のとおりです。

find . -mindepth 2 -type f -print | while read x; do
    y=$(basename "$x")
    if [ -f "$y" ]; then
        mv "$y" "$y".backup
    fi
    mv "$x" "$y"
done

答え2

mvディレクトリーでない場合に target コマンドの単純バックアップを作成するには、次のようにします。

if [ -e "$target" ] && [ ! -d "$target" ]; then
    mv "$target" "$target.backup"
fi

$target.backup既存のディレクトリであれば、明らかに望ましくない結果につながります。また、既存の項目が$target.backupある場合は上書きされます。

列挙バックアップ方式を使用する方が安全です。

mvディレクトリーでない場合に target コマンドの列挙バックアップを作成するには、次のようにします。

suffix=1
if [ -e "$target" ] && [ ! -d "$target" ]; then
    while [ -e "$target.$suffix" ]; do
        suffix=$(( suffix + 1 ))
    done

    mv "$target" "$target.$suffix"
fi

これにより、$targetファイル名を無効にする$target.N最初の正の整数名が変更されます。N$target.N

しかし、ここには競争条件があることに注意してください。その他このコードのインスタンス(または完全に関連していないプロセス)は、名前が$target.$suffix使用されていないことを検出して$targetその名前に移動する間に生成できます。

これを防ぐには:

suffix=1
if [ -e "$target" ] && [ ! -d "$target" ]; then
    while [ -d "$target.$suffix" ] ||
          ! ln "$target" "$target.$suffix" 2>/dev/null; do
        suffix=$(( suffix + 1 ))
    done
fi

ln今私たちは新しい名前(ハードリンク)$target.の場合、既存のディレクトリの名前を生成する整数もスキップされます。無料の新しい名前が見つかるまで、この操作は失敗します。

それからあなたはできます

mv "$source" "$target"

find以前と同様に、すべての一般ファイルを移動するには、次のコマンドを適用します。

find . -mindepth 2 -type f -print -exec sh -c '
    for source do
        target=${source##*/}
        suffix=1

        if [ -e "$target" ] && [ ! -d "$target" ]; then
            while [ -d "$target.$suffix" ] ||
                  ! ln "$target" "$target.$suffix" 2>/dev/null; do
                suffix=$(( suffix + 1 ))
            done
        fi

        mv "$source" "$target"
    done' sh {} +

テスト:

$ tree
.
|-- dir1
|   `-- file
|-- dir2
|   `-- file
`-- dir3
    `-- file

3 directories, 3 files
$ # the find command goes here
./dir1/file
./dir2/file
./dir3/file
$ tree
.
|-- dir1
|-- dir2
|-- dir3
|-- file
|-- file.1
`-- file.2

3 directories, 3 files

この例では、最後に見つかったファイル、以前に見つけたファイル、最初に見つかったファイルにfileなります。filefile.2file.1find


残念ながら、macOSでの実装はmv -n利用可能な終了ステータスを返しません。実行が失敗したときにゼロ以外の値が返された場合は、よりmv少ない競合状態を使用してより簡単な方法で問題を解決できます。

答え3

これが私の最終結果です。

num=1
find . -mindepth 2 -type f -print | while read x; do
    y=$(basename "$x")
    if [ -f "$y" ]; then
        mv "$y" "$y"."$num"
        num=$(( $num + 1 ))
    fi
    mv "$x" "$y"
done

したがって、.backupを使用しないでください。同じ名前の別のバックアップがある場合は、まだ発生する可能性があります。インスピレーションありがとうございます!

関連情報