シェル芸で実現するいい感じなssh接続

前に自分のブログとかに書いてる内容だけど、シェル芸アドベントカレンダーができてたのでそれ向けにまとめてみる。

仕事でサーバをいじるといった場合、割合的にはLinuxサーバが多いと思うので、大体はsshで接続することになると思う。
で、ここではssh接続時に便利だったシェル芸をまとめてみることにする。


## 1. ローカルにあるbashrcをリモートマシンで直接利用する

bashのプロセス置換を利用するためログインシェルがbashである必要はあるのだが、ローカルにおいてあるbashrcをファイル転送せず、そのままリモートマシンのbashでssh経由で利用することができる。

```bash
ssh -t user@host 'bash --rcfile <(echo -e '$(cat /path/to/local_rc1 /path/to/local_rc2 ...|base64)'|base64 -d)'
```

`/path/to/local_rcX`にローカルのbashrcのPATHを書いていく。残念ながらsourceコマンドで分割したファイルの読み込みはできないので、分割してるファイルは個別に指定する必要がある。
似たようなツールで[sshrc](https://github.com/Russell91/sshrc)というシェルスクリプトがあるのだが、sshrcと違ってこの方法だと一時ファイルもリモートに残さないので環境を汚さないという利点がある。
長くて覚えられない・叩けないといった場合は、functionにしておくか[pet](https://github.com/knqyf263/pet)みたいなsnippet管理ツールに登録しておくと良いかもしれない。


### ローカルのvimrcやtmux.confもリモートで利用させる

上記の方法だとbashrcの内容しかリモートに渡せないのだけど、ひと工夫することでvimやtmuxの設定もそのままssh先で利用することができる(ちょっと複雑なので改行入れてる)。

```bash
ssh -t user@host '
    bash --rcfile <(
        echo -e ' $(cat <(echo "function lvim() { vim -u <(echo "$(cat ~/.vimrc|base64)"|base64 -d) \$@ ; }") \
                        ~/dotfiles/{.bashrc,sh_function,sh_alias,bash_prompt} \
                        <(echo -e alias vim=lvim) | \
                        base64
                   ) ' \
        |base64 -d)'
```

やってることは単純で、ローカルの.vimrcの内容をbase64にしてそれをプロセス置換から読み込む`lvim`というfunctionを作り、aliasで置き換えているだけだ。

* [元ネタ](https://orebibou.com/2018/10/%e3%82%b7%e3%82%a7%e3%83%ab%e8%8a%b8%e3%81%a7%e3%80%81%e3%83%ad%e3%83%bc%e3%82%ab%e3%83%ab%e3%81%ab%e3%81%82%e3%82%8bbashrc%e3%82%84vimrc%e3%82%92ssh%e6%8e%a5%e7%b6%9a%e5%85%88%e3%81%a7%e3%83%95/)


### Dockerでも似たような事ができる

原理的には接続先のbashにプロセス置換を利用してコマンドの出力をファイルとして渡しているだけなので、Dockerのシェルでも同様のことができる。

```bash

docker run --rm -it コンテナ bash -c '/bin/bash --rcfile <(echo -e '$(cat ~/dotfiles/{.bashrc,sh/{sh_function,sh_export,sh_alias,sh_function_lvim},bash/bash_prompt}|base64)'|base64 -d)'
```


## 2. ターミナルログをTeratermログっぽくタイムスタンプ付きでローカルに記録する

クライアントマシンがWindowsだったりすると、ssh接続にTeratermを使っていた場合が多いと思う。
そういった場合だと、Teratermログで作業の証跡を取るといった文化があったりすると思う。そのとき、(自分が今まで見てきた限りだけど)ログの行頭にタイムスタンプを付与して記録するといった場合が多い。

通常、一般的に使われているLinuxディストリビューションやMacOSには、ターミナルログを記録する`script`コマンドというものが用意されているのだけど、残念ながらこのコマンドには行頭にタイムスタンプを追加するような機能はない。
そういった処理をscriptコマンドで実現する場合は、以下のようにコマンドを実行すると可能になる。

```bash
script -fq >(awk '{print strftime("%F %T ") $0}{fflush()}'>> LOG_PATH)
```

上でやっている事を簡単に説明すると、scriptコマンドでターミナルログを記録するファイルを指定する際にプロセス置換を利用し、ファイルの代わりにawkコマンドの処理を指定している。
ファイル代わりに指定されたawkコマンド側では、受け付けた入力値の頭にタイムスタンプを付与して、即時LOG_PATHに書き込みをするという流れになっている。

scriptコマンドでは実行コマンドの指定もできるので、ssh接続と同時にログの記録を開始(そして接続終了時に自動終了)することも可能だ。
ただ、MacOSとLinuxだとscriptコマンドのオプションが違うので注意が必要だ。

```bash
# Linuxの場合
script -fq -c "コマンド" >(awk '{print strftime("%F %T ") $0}{fflush() }'>> PATH)

# MacOSの場合
script -Fq >(awk '{print strftime("%F %T ") $0}{fflush() }'>> PATH) コマンド("などで囲まない)
```

* [元ネタ](https://orebibou.com/2017/02/script%e3%82%b3%e3%83%9e%e3%83%b3%e3%83%89%e3%81%a7%e8%a8%98%e9%8c%b2%e3%81%99%e3%82%8b%e3%82%bf%e3%83%bc%e3%83%9f%e3%83%8a%e3%83%ab%e3%83%ad%e3%82%b0%e3%81%ab%e3%82%bf%e3%82%a4%e3%83%a0%e3%82%b9/)

## 3. ターミナルの背景色・文字色をコマンドから変更する

(これはあまりシェル芸とは言えないと思うのだけど)ssh接続する際に便利だと思うので載せておく。
一般的によく利用されているターミナルエミュレータでは、OSCエスケープシーケンスというものがサポートされている。ターミナルエミュレーターによって書き方は異なるものの、これを利用すると端末の文字色や背景色、ものによってはプロファイルの切り替えなんかも行えたりする。
printfやechoえ定のエスケープシーケンスを出力するだけなので、これを利用して、このサーバに接続する際は青、こっちのサーバは赤といった指定をssh接続時や接続終了時に行うことで、間違えて本番環境でコマンドを実行してしまうといった悲劇が発生する確率を下げることができる(…かもしれない)。

### iTerm2の場合

iTermの場合、独自のOSCエスケープシーケンスが使えるようになってて、プロファイルの変更もできる。
(画像とかうまくアップできなかった…一応GIFがあるので、気になる人は[元ネタ](https://orebibou.com/2018/12/iterm2%e3%81%a7%e3%82%b3%e3%83%b3%e3%82%bd%e3%83%bc%e3%83%ab%e3%81%8b%e3%82%89%e3%82%b3%e3%83%9e%e3%83%b3%e3%83%89%e3%82%92%e5%ae%9f%e8%a1%8c%e3%81%97%e3%81%a6%e3%83%97%e3%83%ad%e3%83%95%e3%82%a1/)の方へ…)

```bash
printf "\E]50;SetProfile=プロファイル名\a" # 指定したプロファイルに変更する
printf "\E]1337;SetColors=bg=E\a\E]1337;SetColors=fg=ccc\a" # 文字色・背景色を変更する(RGBを0〜fで指定)
```


### GnomeTerminalの場合

GnomeTerminalの場合、以下のようなコマンドでプロファイルの変更はできないが背景色・文字色の変更は可能。

```bash
echo -ne '\e]10;#000000\a' # 文字色を変更
echo -ne '\e]11;#ffffff\a' # 背景色を変更
```

Termineterなど、Linuxで使える他のターミナルエミュレーターでも同様の書き方で動作すると思われる(ちゃんと確認したわけではない)。

* [元ネタ](https://orebibou.com/2019/02/osc%e3%82%a8%e3%82%b9%e3%82%b1%e3%83%bc%e3%83%97%e3%82%b7%e3%83%bc%e3%82%b1%e3%83%b3%e3%82%b9%e3%82%92%e4%bd%bf%e3%81%a3%e3%81%a6gnome%e3%82%bf%e3%83%bc%e3%83%9f%e3%83%8a%e3%83%ab%e3%81%a7%e7%8f%be/)

### Windowsの場合

Windowsの場合はちゃんと調べてないのだけど、[去年調べた限り](https://orebibou.com/2018/09/wsl%e3%81%a7%e3%82%b3%e3%83%9e%e3%83%b3%e3%83%89%e3%81%8b%e3%82%89%e3%82%bf%e3%83%bc%e3%83%9f%e3%83%8a%e3%83%ab%e3%81%ae%e8%89%b2%e3%82%92%e5%a4%89%e6%9b%b4%e3%81%99%e3%82%8b/)だとWSLではColorTool.exeというものを使えばコマンドでターミナルの背景色・文字色が設定できた。
あと触ってないけど、[Windows TerminalではOSCエスケープシーケンスが使えるという情報](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences)があるので、GnomeTerminalなどと同様の処理ができるかもしれない。

## さいごに

最近はWindowsでもWSLが使えるようになって、bashrcなどをいじって好みの設定で使ってる人も多いと思うので、その設定をリモートでも使えたら効率もアップするだろう。
この辺の情報がいい感じなターミナルライフの一助になったら幸いです。

さいごに自分の宣伝になってしまうのですが、上の2個の処理をある程度簡単にできるようにしてあるTUIのsshクライアントを個人的に作ってるので、よければ見てもらえれば…(´・ω・｀)。
PureGoでリスト選択してssh接続するんですが、普通にインタラクティブな方式で接続する他にパラレル接続してのコマンド実行も可能にしてます。
(一応、マルチプロキシ接続やPKCS11、ssh-agentなんかにも対応してます。)

* [blacknon/lssh: List selection type alternative ssh/scp/sftp client. Pure Go.](https://github.com/blacknon/lssh) ![](http://b.hatena.ne.jp/entry/image/https://github.com/blacknon/lssh)