特定のファイルとディレクトリを検索する find コマンドがあります。その後、 find コマンドは、以前に見つかったファイルとディレクトリをソースとして使用して rsync を実行します。問題は、これらのファイルやディレクトリにWindowsなどの違法な文字だけでなく、単一引用符、二重引用符など、さまざまな文字を含めることができることです。
rsyncまたは他のコマンドで使用するために文字列を動的にエスケープするにはどうすればよいですか?
このコマンドは、rsyncソース文字列に二重引用符をハードコーディングすることで機能しますが、文字列に二重引用符が含まれていると中断されます。
find "/mnt/downloads/cache/" -depth -mindepth 1 \( \
-type f \! -exec fuser -s '{}' \; -o \
-type d \! -empty \) \
\( -exec echo rsync -i -dIWRpEAXogt --numeric-ids --inplace --dry-run '"{}"' "${POOL}" \; \)
結果出力:
rsync -i -dIWRpEAXogt --numeric-ids --inplace --dry-run "test/this " is an issue" /mnt/backing
回答の情報を適用した後の作業コマンド:
find "/mnt/downloads/cache/" -depth -mindepth 1 \( \
-type f \! -exec fuser -s {} \; -o \
-type d \! -empty \) \
\( -exec rsync -i -dIWRpEAXogt --remove-source-files-- "${POOL} \; \) \
-o \( -type d -empty -exec rm -d {} \; \)
ベストアンサー1
あなたの引用の問題は、あなたが持っていない問題を解決しようとするために発生します。パラメータ引用符はシェルを扱う場合にのみ必要であり、直接find
呼び出すとrsync
シェルは関連しません。ビジュアル出力を使用することは、各パラメータの始まりと終わりを確認できないため、動作するかどうかを確認するための良い方法ではありません。
これが私が意味するものです:
# touch "foo'\"bar"
# ls
foo'"bar
# find . -type f -exec stat {} \;
File: ‘./foo'"bar’
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: fd00h/64768d Inode: 1659137 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1004/ phemmer) Gid: ( 1004/ phemmer)
Access: 2017-12-09 13:21:28.742597483 -0500
Modify: 2017-12-09 13:21:28.742597483 -0500
Change: 2017-12-09 13:21:28.742597483 -0500
Birth: -
{}
argでは引用しませんでしたstat
。
ただし、rsync
一致するすべてのファイルを呼び出すため、コマンドのパフォーマンスが非常に低下します。この問題を解決する方法は2つあります。
他の人が指摘したように、ファイルのリストをrsync
標準入力にパイプすることができます。
# find . -type f -print0 | rsync --files-from=- -0 . dest/
# ls dest/
foo'"bar
ファイル名にヌルバイトを含めることはできないため、ファイル名区切り文字としてヌルバイトを使用します。
GNUを使用している場合をfind
呼び出す別の方法があります。-exec
つまり、-exec {} +
このスタイルではfind
複数の引数が一度に渡されます。ただし、すべてのパラメータはコマンドの途中ではなくコマンドの最後に追加されます。小さなシェルを介してパラメータを渡すと、この問題を解決できます。
# find . -type f -exec sh -c 'rsync "$@" dest/' {} +
# ls dest/
foo'"bar
これにより、ファイルのリストが渡され、sh
次に置き換えられます。"$@"