TL;DR
Fix scp command failure · noraworld/dotfiles@4d7cf4f
はじめに
たとえば ~/.bashrcなどで、echoコマンドなどを使って何かを出力するようにしていると scpコマンドが失敗します。
# リモートホスト側echo"something"# クライアント側$ scp username@example.com:~/test .
something
ファイルがカレントディレクトリにダウンロードされるはずがダウンロードされず、"something" と表示されただけで終わってしまいます。
ログイン時に標準出力に何かを表示するようにしていると scpコマンドが失敗するらしいので、scpコマンド実行時のみ ~/.bashrcなどで何も出力しないようにします。
やり方
scpでのログインかどうかを判定する is_not_scp()関数を作ります。is_not_scp()関数は scpからのログインでなければ trueを返し、scpからのログインだったら falseを返します。
そして、scpだったら、ログイン時に何かを出力するようにしている部分を出力しないようにします。
is_not_scp(){if[!-f /proc/$PPID/cmdline ];then
echo true
elif[-f /proc/$PPID/cmdline ]&&[["$(cat /proc/$PPID/cmdline | sed's/\x0//g')"=~ sshd:([[:blank:]]+.*)@notty ]];then
echo false
else
echo true
fi}if"$(is_not_scp)";then
echo"something"fi解説
macOS では /proc/$PPID/cmdlineは存在しないのでスキップします。
Linux では /proc/$PPID/cmdlineに現在ログイン中の端末の情報が表示されます。たとえば SSH ログイン中に実行すると以下のように表示されます。
$ cat /proc/$PPID/cmdline
sshd: ubuntu@pts/0
これが scpコマンドだと以下のようになります。
sshd: ubuntu@notty
nottyは端末が割り当てられていないということなのですが、scpコマンドだと nottyと表示されるので、そうなっていれば scpコマンドからだと判断します1。
sedコマンドを使っているのは、cat /proc/$PPID/cmdlineの出力にヌルバイトが混ざっているからです。sedでヌルバイトを除去しています。
ログイン時に何かを出力している箇所を if "$(is_not_scp)"; thenと fiで囲めば scp時にはその部分は出力されなくなるので、scpがうまく機能するようになります。
~/.bashrcじゃなくて ~/.bash_profileに何かを出力していたり、Zsh を使っていて ~/.zshrcとかに何かを出力していた場合も同様です。適宜、ファイル名は読み替えてください。
参考サイト
それ以外で
sshd: ubuntu@nottyのように表示されるケースもありますが実用上はおそらく問題ないと思いますので割愛します。 ↩