"find -exec mv"は以前に移動されたのと同じファイルを移動しようとします。

"find -exec mv"は以前に移動されたのと同じファイルを移動しようとします。

私の間違ったコマンド:

find . -type f -name '*2019*' -exec mv {} ./backup_2019 \;

結果:

mv: ‘./backup_2019/2019-A.txt’ and ‘backup_2019/2019-A.txt’ are the same file
mv: ‘./backup_2019/2019-B.txt’ and ‘backup_2019/2019-B.txt’ are the same file
mv: ‘./backup_2019/2019-C.txt’ and ‘backup_2019/2019-C.txt’ are the same file

以前に移動したファイルを見つけたと思います。 MaxDeepthを使用せずにこの問題を解決できますか?ターゲットディレクトリのみを除外する方法はありますか?

答え1

除外するターゲットディレクトリを無視する必要があります。

find . -path './backup_2019' -prune -o -type f -name '*2019*' -exec mv {} ./backup_2019 \;

演算子間の暗黙的なANDは-oOR()よりも密接に関連付けられているため、次のように変換されます。(パスが一致する場合はスキップ./backup_2019)または(mv一致するファイルがある場合*2019*

答え2

findバックアップディレクトリに入らないようにするには、そのディレクトリを無視する必要があります。すでに持っている回答これを行う方法を教えてください。

ただし、この方法でファイルをバックアップすると、データが削除される危険性があります。異なるサブディレクトリにある複数のファイルが同じ名前を持つ場合は、ターゲットバックアップディレクトリが上書きされます。

データをバックアップするには、実際のバックアップソフトウェア(たとえば、resticこれが不可能な場合はバックアップするファイルの相対パスを維持するソリューションを使用します。

次のコマンドは、名前に部分文字列を含むすべてのファイルをディレクトリにrsyncコピー(移動しない)します。2019backup_2019

rsync --itemize-changes --archive --prune-empty-dirs \
    --exclude='/backup_2019/***' --include='*/' --include='*2019*' --exclude='*' \
    ./ ./backup_2019

./backup_2019これにより、転送するファイルやディレクトリを内部的に検索せずに、部分文字列を含むすべてのエントリをコピーします2019。最終的にターゲットの空のディレクトリは削除されます。コピーされた内容はすべて、backup_2019現在のディレクトリのファイルと同じ場所にコピーされます。

例:

$ tree -F
.
|-- dir1/
|   |-- file-1
|   |-- file-2019-A
|   `-- subdir/
|       |-- file-2
|       `-- file-2019-B
|-- dir2/
|   |-- file-1
|   |-- file-2019-A
|   `-- subdir/
|       |-- file-2
|       `-- file-2019-B
`-- dir3/
    |-- file-1
    |-- file-2019-A
    `-- subdir/
        |-- file-2
        `-- file-2019-B
$ rsync --itemize-changes --archive \
    --prune-empty-dirs \
    --exclude='/backup_2019/***' --include='*/' --include='*2019*' --exclude='*' \
    ./ ./backup_2019
cd+++++++++ ./
cd+++++++++ dir1/
>f+++++++++ dir1/file-2019-A
cd+++++++++ dir1/subdir/
>f+++++++++ dir1/subdir/file-2019-B
cd+++++++++ dir2/
>f+++++++++ dir2/file-2019-A
cd+++++++++ dir2/subdir/
>f+++++++++ dir2/subdir/file-2019-B
cd+++++++++ dir3/
>f+++++++++ dir3/file-2019-A
cd+++++++++ dir3/subdir/
>f+++++++++ dir3/subdir/file-2019-B
$ tree -F
.
|-- backup_2019/
|   |-- dir1/
|   |   |-- file-2019-A
|   |   `-- subdir/
|   |       `-- file-2019-B
|   |-- dir2/
|   |   |-- file-2019-A
|   |   `-- subdir/
|   |       `-- file-2019-B
|   `-- dir3/
|       |-- file-2019-A
|       `-- subdir/
|           `-- file-2019-B
|-- dir1/
|   |-- file-1
|   |-- file-2019-A
|   `-- subdir/
|       |-- file-2
|       `-- file-2019-B
|-- dir2/
|   |-- file-1
|   |-- file-2019-A
|   `-- subdir/
|       |-- file-2
|       `-- file-2019-B
`-- dir3/
    |-- file-1
    |-- file-2019-A
    `-- subdir/
        |-- file-2
        `-- file-2019-B

13 directories, 18 files

バックアップされたファイルの「コピー」の代わりに「移動」を実行する--remove-source-filesオプションをリストに追加できます。rsync

答え3

まだ解決策が見つからない場合は、maxlengthオプションを試してください。または、現在検索されているサブフォルダ以外のフォルダにバックアップしてみてください。

前に発見しました。 -最大深さ1 -name"2019-exec mv '{}' ./backup_2019;

答え4

まあ、これは予想外の悪い驚きだった。とにかく忘れて、-exec他のことを試してみてください。

find . -type f -name '*2019*' -print0 | while read -d $'\0' fpath; do mv "$fpath" ./backup_2019; done

ここでは、スクリプトがスペースを含むファイル名をサポートするように、スペース(デフォルト)を区切り文字としてNULL文字として追加して-print0置き換えます。-d $'\0'

パイプを使用すると、サブシェルが作成され、「グローバル」スクリプト変数へのアクセスが失われます。

ループ内で「グローバル変数」にアクセスする必要がある場合は、パイプの代わりにプロセス置換を使用できます。

myvar=""
while read -d $'\0' fpath 
do 
  mv "$fpath" ./backup_2019
  myvar="Hello World" 
done < <(find . -type f -name '*2019*' -print0)

関連情報