
私の間違ったコマンド:
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は-o
OR()よりも密接に関連付けられているため、次のように変換されます。(パスが一致する場合はスキップ./backup_2019
)または(mv
一致するファイルがある場合*2019*
)。
答え2
find
バックアップディレクトリに入らないようにするには、そのディレクトリを無視する必要があります。すでに持っている回答これを行う方法を教えてください。
ただし、この方法でファイルをバックアップすると、データが削除される危険性があります。異なるサブディレクトリにある複数のファイルが同じ名前を持つ場合は、ターゲットバックアップディレクトリが上書きされます。
データをバックアップするには、実際のバックアップソフトウェア(たとえば、restic
これが不可能な場合はバックアップするファイルの相対パスを維持するソリューションを使用します。
次のコマンドは、名前に部分文字列を含むすべてのファイルをディレクトリにrsync
コピー(移動しない)します。2019
backup_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)