ShellScript
Bash
SSH

.bashrc で exit するスクリプトを source しちゃったときの対処法

More than 1 year has passed since last update.


tl;dr



  • source で読み込んだスクリプト内で exit すると、呼び出し元スクリプトごと終了する

  • ↑ を .bashrc でやってしまうとログインができなくなる

  • そうなってしまったらログイン時に Ctrl+C を連打する


背景

自作の便利スクリプトをサーバーログイン時 (厳密には Bash 起動時) に実行させるようにしました。

[togawa@remote01 ~]$ echo 'source ./myscript.sh' >> ./.bashrc

このサーバーを remote01 とし、ログイン元サーバーを local01 とします。


問題

一度 remote01 からログアウトし、再度ログインしたところ そのままログアウト されてしまいました。

[togawa@remote01 ~]$ logout

Connection to xxx.xx.x.xx closed.

[togawa@local01 ~]$ ssh remote01
togawa@xxx.xx.x.xx's password:
Last login: Fri Feb 10 19:04:02 2017 from xxx.xx.x.xx
Connection to xxx.xx.x.xx closed.
[togawa@local01 ~]$

原因は以下の2つが成り立ってしまったためです。


  • スクリプトを .bashrc の source から呼び出していること

  • スクリプト中で exit していること


試したこと


ssh rm

このままではサーバーにログインができません。

とはいえ、 .bashrc が発動する前に問題のスクリプト (myscript.sh) を消せれば良いはずです。

ssh に引数を与えるとそれをコマンドとして実行してくれるので、 rm を渡してみます。

[togawa@local01 ~]$ ssh remote01 rm myscript.sh

togawa@xxx.xx.x.xx's password:
Connection to xxx.xx.x.xx closed.
[togawa@local01 ~]$

結果はだめ。


scp

ssh がだめなら scp はどうだ、ということで空のファイルを転送してスクリプトを 0 byte にする作戦です。

[togawa@local01 ~]$ touch myscript.sh

[togawa@local01 ~]$ ls -l myscript.sh
-rw-r--r-- 1 togawa togawa 0 2月 10 19:48 myscript.sh

[togawa@local01 ~]$ scp ./myscript.sh remote01:~
togawa@xxx.xx.x.xx's password:
Connection to xxx.xx.x.xx closed.
[togawa@local01 ~]$

これもだめでした。 ssh/scp では律儀に .bashrc が読み込まれてしまいます。


Bash の起動を止める

ServerFault という Stackoverflow 風味のサイトでは、「.bashrc がロードされる前に Ctrl + C で Bash の起動を中止させるといいよ」という回答がありました。

http://serverfault.com/questions/206544/i-screwed-up-exit-in-bashrc

ssh 実行 → ログイン先サーバーで bash 起動 → (*) → .bashrc ロード

↑ の (*) のタイミングで Ctrl + C を叩け、とのこと。タイミングがシビアそう。

ssh にデバッグモードの -v オプションをつけてやってみました。

確かにコツが必要でしたが、成る程、何度かやったらうまくいきました。


[togawa@local01 ~]$ ssh -v remote01
OpenSSH_4.3p2, OpenSSL 0.9.8e-fips-rhel5 01 Jul 2008
debug1: Reading configuration data /home/togawa/.ssh/config
debug1: Applying options for remote01
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Applying options for *
debug1: Connecting to xxx.xx.x.xx [xxx.xx.x.xx] port 22.
debug1: Connection established.
debug1: identity file /home/togawa/.ssh/identity type -1
debug1: identity file /home/togawa/.ssh/id_rsa type 1
debug1: identity file /home/togawa/.ssh/id_dsa type -1
debug1: loaded 3 keys
debug1: Remote protocol version 2.0, remote software version OpenSSH_6.6.1
debug1: match: OpenSSH_6.6.1 pat OpenSSH*
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_4.3
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: server->client aes128-ctr hmac-md5 none
debug1: kex: client->server aes128-ctr hmac-md5 none
debug1: SSH2_MSG_KEX_DH_GEX_REQUEST(1024<1024<8192) sent
debug1: expecting SSH2_MSG_KEX_DH_GEX_GROUP
debug1: SSH2_MSG_KEX_DH_GEX_INIT sent
debug1: expecting SSH2_MSG_KEX_DH_GEX_REPLY
debug1: Host 'xxx.xx.x.xx' is known and matches the RSA host key.
debug1: Found key in /home/togawa/.ssh/known_hosts:42
debug1: ssh_rsa_verify: signature correct
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: SSH2_MSG_SERVICE_REQUEST sent
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
debug1: Trying private key: /home/togawa/.ssh/identity
debug1: Offering public key: /home/togawa/.ssh/id_rsa
debug1: Authentications that can continue: publickey,password
debug1: Trying private key: /home/togawa/.ssh/id_dsa
debug1: Next authentication method: password
togawa@xxx.xx.x.xx's password:
debug1: Authentication succeeded (password).
debug1: channel 0: new [client-session]
debug1: Entering interactive session.
debug1: Sending environment.
debug1: Sending env LANG = ja_JP.UTF-8
Last login: Fri Feb 10 19:30:13 2017 from xxx.xxx.x.xx
^C-bash-4.2$ ^C
-bash-4.2$ ^C
-bash-4.2$ ^C
-bash-4.2$ ^C
-bash-4.2$ ^C
-bash-4.2$
-bash-4.2$ ls
myscript.sh
-bash-4.2$ rm myscript.sh
-bash-4.2$ ls
-bash-4.2$
-bash-4.2$

Bash キャンセル (各ゲーっぽい) が成功すると $PS1 が読み込まれていない、すなわち .bashrc が読み込まれていないことがわかります。

これによりログイン先サーバーで操作が可能になるので、問題のスクリプトを rm すれば万事解決です。


教訓

シェルスクリプトではむやみに source を使わない。