-execを使用して、文字列から不明な文字をエスケープします。

-execを使用して、文字列から不明な文字をエスケープします。

特定のファイルとディレクトリを検索する 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次に置き換えられます。"$@"

おすすめ記事