SSHでリモートにコマンド実行する方法とその際にクォーテーションのエスケープを気にしないようにする方法

2017/07/08

SSHを通してリモート先でコマンド実行するには、ssh $remote '$command $option'というようにsshの最後にコマンドを書く。コマンド部分をくくるクォーテーションと、コマンド内部でクォーテーションを使用した時のエスケープについて書く。

目次

クォーテーションが必要ない場合

ls /var/tmpのような簡単なコマンドであれば、実行コマンドをシングルクォーテーションやダブルクォーテーションでくくる必要はない。

クォーテーションが必要な場合

複数のコマンドをつなぐ時

&&;で複数のコマンドを実行したりする場合は、クォーテーションでくくらなくてはいけない。

コマンドのオプション部分でクォーテーションが使われている場合

他にはsedで置換するときにexpression部分をシングルクォーテーションで囲むとき等はsedコマンド自体をダブルクォーテーションでくくらなければいけない。簡単な置換であればexpression部分をシングルクォーテーションで囲まなくてもいいが、後方参照をするために拡張正規表現のグルーピング()を使った場合などは、expressionをクォーテーションで囲む必要が出てくるので、sedをSSHを通して実行する場合はsedコマンド自体をクォーテーションでくくらなければいけないことが多いだろう。

シングルクォーテーションかダブルクォーテーションか

SSH越しに実行するコマンドにコマンド置換や変数が含まれていた場合、手元のサーバかリモート先かどちらのサーバで解釈させたいかによって、コマンドにシングルクォーテーションをつけるかダブルクォーテーションをつけるかが変わる。シングルクォーテーションをつけないと、手元のサーバでコマンドの解釈がされた上でSSH先にコマンドが送られる。シングルクォーテーションをつけると、コマンド置換や変数の展開が行われないので、コマンドで書いた字面そのままがリモート先に送られ、実行される。

ここまでが、SSHを通してリモート先でコマンドを実行する基本的な文法の説明で、今回の一番書きたいことであるクォーテーションを気にしないで実行する方法について以降で考えてみたい。

クォーテーションのエスケープ

題材として、ApacheのLog出力の最後に%Dを追加してレスポンスタイムをマイクロ秒でログ出力するためのconf編集をsedを使って行う。

sedの置換式の中にダブルクォーテーションがあったとき、置換式のダブルクォーテーションと置換式をくくるシングルクォーテーション、そしてSSHを通して実行するのでsedコマンド自体をくくるクォーテーションが必要になる。クォーテーションだらけで訳が分からなくなってしまう。
今回の題材を実現するためには置換式の中にダブルクォーテーションが出てくる。

sedコマンド

これをSSH越しで実行するためにはsedをダブルクォーテーションで囲み、置換式の中に出てくるダブルクォーテーションを\でエスケープする必要がある。

もしエスケープ箇所が増えたらものすごく読みづらい置換式になってしまう。

クォーテーションのエスケープを書かなくても済む方法

これを解決する方法としては、エスケープしていない通常のsedコマンドをファイルに記載してスクリプトファイルをSSHを通して実行する方法がある。ssh $remote sh < ファイルでリモート先でスクリプトファイルを配布せずに実行できる。

スタンダードなやり方だが、スクリプトファイル、つまりここでは中間ファイルができてしまうのが好みでないので、中間ファイルを作らずに実行する方法を考える。

クォーテーションのエスケープを書かなくても済むスマートな方法

ターミナルに入力したクォーテーションを標準出力にそのまま出す方法として考えられるのは、ヒアドキュメントを利用する方法がある。
echoでスクリプトファイルに書かれているものと同じコマンドを出力しようとしても、シングルクォーテーションが削られて出力される。

ヒアドキュメントを使うと、エスケープを書かずに出力できる。

ヒアドキュメントを使うとき、大抵cat <<EOS > output_fileのようにファイルに書き出すが、今回は出力先をファイルではなく、パイプでつないだssh $remote shにする。技術的にはスクリプトファイルをリダイレクトするものとほぼ同じになる。

server1からserver100の複数のサーバに実行したい場合、for loopと組み合わせて次のように書ける。

-Linux
-, ,