ソースパスにスペースが含まれているbashスクリプトのSCPエラー

ソースパスにスペースが含まれているbashスクリプトのSCPエラー

もちろん私は簡単なものを見逃していますが、それは私を狂わせます。リモートファイルを現在のローカルディレクトリにSCPに送信しようとしています。リモートパスにスペースがあります。ファイルから読み取るため、スクリプトで実行し、パスを変数に入れる必要があります。

問題は、エスケープしようとしても、「ファイルまたはディレクトリが見つかりません」というエラーが引き続き発生することです。-vコマンドにオプションを追加しscpてコピーして貼り付けると、コマンドは機能しますが、そこに変数があると爆発します。

パスを作成すると正常に機能しますが、パスを変数に入れようとすると操作が中断されます。ハードコーディングされた文字列をエスケープすることに関する同様の質問がたくさんありますが、ファイルパスにスペースがある変数を使用する質問は見つかりません。

ファイルパスは次のとおりです。 /home/myUser/databases/SONIC BOATS LTD./database-1.11-2019-12-30-09-40.zip

verbose を実行すると、scpこの行は以下をsending command印刷します。

 scp -f /home/myUser/databases/SONIC\\ BOATS\\ LTD./database-1.11-2019-12-30-09-40.zip .

その行をスクリプトに貼り付けて実行すると機能します。それでは、変数があるスクリプトで実行するとなぜ動作しませんか?

私の変数は次のように印刷されます。

DB_ARC_FILENAME:

/home/myUser/databases/SONIC BOATS LTD./database-1.11-2019-12-30-09-40.zip

ESC_DB_ARC_FILENAME

/home/myUser/databases/SONIC\ BOATS\ LTD./database-19.11-2019-12-30-09-40.zip

私のスクリプトコードスニペット:

while read DB_ARC_FILENAME
do
        # Escape spaces in the files name
        ESC_DB_ARC_FILENAME=${DB_ARC_FILENAME//\ /\\\ }

        # Copy the database file to the local system
        scp -v [email protected]:"$ESC_DB_ARC_FILENAME" .
...

done < uploadedDatabaseFileList

これは私が実行したときに得られる結果です。

debug1: Sending command: scp -v -f /home/myUser/databases/SONIC\\ BOATS\\ LRD./database-1.11-2019-12-30-09-40.zip
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug1: client_input_channel_req: channel 0 rtype [email protected] reply 0
: No such file or directoryer/databases/SONIC BOATS LTD./database-1.11-2019-12-30-09-40.zip
debug1: channel 0: free: client-session, nchannels 1
: No such file or directoryes/SONIC BOATS LTD./database-1.11-2019-12-30-09-40.zip
debug1: fd 0 clearing O_NONBLOCK
debug1: fd 1 clearing O_NONBLOCK
Transferred: sent 2836, received 2704 bytes, in 0.8 seconds
Bytes per second: sent 3678.9, received 3507.7
debug1: Exit status 1

答え1

脱出パターンが正しくありません。各スペースの前にバックスラッシュを追加するこのオプションを使用します。

ESC_DB_ARC_FILENAME="${DB_ARC_FILENAME// /\\ }"

テストシナリオ(中$HOME):

file='the date.txt'
date > "$file"

scp -vp localhost:"$file" td; ls -l td; rm -f td             # Fails
scp -vp localhost:"${file// /\\ }" td; ls -l td; rm -f td    # Succeeds

知っていた。このエラーメッセージはこれを知らせます。

: No such file or directoryes/SONIC BOATS LTD./database-1.11-2019-12-30-09-40.zip

Windowsコンピュータで生成されたソースデータファイルを使用しています。もちろん、ソースファイルにはそのような文字はありませんが、末尾のCRはファイル名の一部と見なされます。

答え2

Bashスクリプトを使用してスペースを含むリモートパスからファイルをコピーしようとしたときにscp同様の問題が発生しました。

私が思いついた解決策は次のとおりです。

二重引用符+オプションを使用してください-T

scp -T user@host:"'<path-with-spaces>'" <destination>
scp -T user@host:'"<path-with-spaces>"' <destination>
scp -T user@host:"\"<path-with-spaces>\"" <destination>

注:オプションがない場合、-Tこれらのコマンドはprotocol error: filename does not match request理由を詳しく説明します。ここ

printfのエスケープパスを使用してください。

source="<path-with-spaces>"
printf -v source "%q" "${source}"
scp user@host:"${source}" <destination>

注:このオプションはオプションなしでうまく機能します-Tが、単一のファイルに対してのみ機能します。複数のファイルの場合は、-Tオプションが必要です(上記と同じエラー)。

関連情報