🐈

ログイン時に何かを出力するようにしていると scp が失敗する問題の対処法

2021/03/03に公開

TL;DR

Fix scp command failure · noraworld/dotfiles@4d7cf4f

はじめに

たとえば ~/.bashrc などで、echo コマンドなどを使って何かを出力するようにしていると scp コマンドが失敗します。

~/.bashrc
# リモートホスト側
echo "something"
# クライアント側
$ scp username@example.com:~/test .
something

ファイルがカレントディレクトリにダウンロードされるはずがダウンロードされず、"something" と表示されただけで終わってしまいます。

ログイン時に標準出力に何かを表示するようにしていると scp コマンドが失敗するらしいので、scp コマンド実行時のみ ~/.bashrc などで何も出力しないようにします。

やり方

scp でのログインかどうかを判定する is_not_scp() 関数を作ります。is_not_scp() 関数は scp からのログインでなければ true を返し、scp からのログインだったら false を返します。

そして、scp だったら、ログイン時に何かを出力するようにしている部分を出力しないようにします。

~/.bashrc
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)"; thenfi で囲めば scp 時にはその部分は出力されなくなるので、scp がうまく機能するようになります。

~/.bashrc じゃなくて ~/.bash_profile に何かを出力していたり、Zsh を使っていて ~/.zshrc とかに何かを出力していた場合も同様です。適宜、ファイル名は読み替えてください。

参考サイト

脚注
  1. それ以外で sshd: ubuntu@notty のように表示されるケースもありますが実用上はおそらく問題ないと思いますので割愛します。 ↩︎

GitHubで編集を提案

Discussion