前に自分のブログとかに書いてる内容だけど、シェル芸アドベントカレンダーができてたのでそれ向けにまとめてみる。
仕事でサーバをいじるといった場合、割合的にはLinuxサーバが多いと思うので、大体はsshで接続することになると思う。
で、ここではssh接続時に便利だったシェル芸をまとめてみることにする。
1. ローカルにあるbashrcをリモートマシンで直接利用する
bashのプロセス置換を利用するためログインシェルがbashである必要はあるのだが、ローカルにおいてあるbashrcをファイル転送せず、そのままリモートマシンのbashでssh経由で利用することができる。
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というシェルスクリプトがあるのだが、sshrcと違ってこの方法だと一時ファイルもリモートに残さないので環境を汚さないという利点がある。
長くて覚えられない・叩けないといった場合は、functionにしておくかpetみたいなsnippet管理ツールに登録しておくと良いかもしれない。
ローカルのvimrcやtmux.confもリモートで利用させる
上記の方法だとbashrcの内容しかリモートに渡せないのだけど、ひと工夫することでvimやtmuxの設定もそのままssh先で利用することができる(ちょっと複雑なので改行入れてる)。
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で置き換えているだけだ。
Dockerでも似たような事ができる
原理的には接続先のbashにプロセス置換を利用してコマンドの出力をファイルとして渡しているだけなので、Dockerのシェルでも同様のことができる。
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コマンドで実現する場合は、以下のようにコマンドを実行すると可能になる。
script -fq >(awk '{print strftime("%F %T ") $0}{fflush()}'>> LOG_PATH)
上でやっている事を簡単に説明すると、scriptコマンドでターミナルログを記録するファイルを指定する際にプロセス置換を利用し、ファイルの代わりにawkコマンドの処理を指定している。
ファイル代わりに指定されたawkコマンド側では、受け付けた入力値の頭にタイムスタンプを付与して、即時LOG_PATHに書き込みをするという流れになっている。
scriptコマンドでは実行コマンドの指定もできるので、ssh接続と同時にログの記録を開始(そして接続終了時に自動終了)することも可能だ。
ただ、MacOSとLinuxだとscriptコマンドのオプションが違うので注意が必要だ。
# Linuxの場合
script -fq -c "コマンド" >(awk '{print strftime("%F %T ") $0}{fflush() }'>> PATH)
# MacOSの場合
script -Fq >(awk '{print strftime("%F %T ") $0}{fflush() }'>> PATH) コマンド("などで囲まない)
3. ターミナルの背景色・文字色をコマンドから変更する
(これはあまりシェル芸とは言えないと思うのだけど)ssh接続する際に便利だと思うので載せておく。
一般的によく利用されているターミナルエミュレータでは、OSCエスケープシーケンスというものがサポートされている。ターミナルエミュレーターによって書き方は異なるものの、これを利用すると端末の文字色や背景色、ものによってはプロファイルの切り替えなんかも行えたりする。
printfやechoえ定のエスケープシーケンスを出力するだけなので、これを利用して、このサーバに接続する際は青、こっちのサーバは赤といった指定をssh接続時や接続終了時に行うことで、間違えて本番環境でコマンドを実行してしまうといった悲劇が発生する確率を下げることができる(…かもしれない)。
iTerm2の場合
iTermの場合、独自のOSCエスケープシーケンスが使えるようになってて、プロファイルの変更もできる。
(画像とかうまくアップできなかった…一応GIFがあるので、気になる人は元ネタの方へ…)
printf "\E]50;SetProfile=プロファイル名\a" # 指定したプロファイルに変更する
printf "\E]1337;SetColors=bg=E\a\E]1337;SetColors=fg=ccc\a" # 文字色・背景色を変更する(RGBを0〜fで指定)
GnomeTerminalの場合
GnomeTerminalの場合、以下のようなコマンドでプロファイルの変更はできないが背景色・文字色の変更は可能。
echo -ne '\e]10;#000000\a' # 文字色を変更
echo -ne '\e]11;#ffffff\a' # 背景色を変更
Termineterなど、Linuxで使える他のターミナルエミュレーターでも同様の書き方で動作すると思われる(ちゃんと確認したわけではない)。
Windowsの場合
Windowsの場合はちゃんと調べてないのだけど、去年調べた限りだとWSLではColorTool.exeというものを使えばコマンドでターミナルの背景色・文字色が設定できた。
あと触ってないけど、Windows TerminalではOSCエスケープシーケンスが使えるという情報があるので、GnomeTerminalなどと同様の処理ができるかもしれない。
さいごに
最近はWindowsでもWSLが使えるようになって、bashrcなどをいじって好みの設定で使ってる人も多いと思うので、その設定をリモートでも使えたら効率もアップするだろう。
この辺の情報がいい感じなターミナルライフの一助になったら幸いです。
さいごに自分の宣伝になってしまうのですが、上の2個の処理をある程度簡単にできるようにしてあるTUIのsshクライアントを個人的に作ってるので、よければ見てもらえれば…(´・ω・`)。
PureGoでリスト選択してssh接続するんですが、普通にインタラクティブな方式で接続する他にパラレル接続してのコマンド実行も可能にしてます。
(一応、マルチプロキシ接続やPKCS11、ssh-agentなんかにも対応してます。)