ssh上で複雑なコマンドラインを実行する方法は?

kramer65

リモートホストで実行されているDockerコンテナの環境を取得したい場合があります。これを行うには、ホストにログインします。

ssh [email protected]

次に、次のコマンドを実行します。

sudo docker exec -it `sudo docker ps | grep mycontainername | awk '{print $1;}'` env

これを1つのコマンドで実行したいと思います(3回以上実行し、自動化したいです。.:-))。

これは機能します:

 ssh -t [email protected] sudo docker ps | grep mycontainername

しかし、私がこれを行うとき

ssh -t [email protected] sudo docker exec -it `sudo docker ps | grep mycontainername | awk '{print $1;}'` env

私は得る

"docker exec" requires at least 2 arguments.
See 'docker exec --help'.

Usage:  docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

Run a command in a running container
Connection to 123.456.789.10 closed.

誰かが私がこれを実行する方法を知っていますか?

カミル・マシオロフスキー

一般的な所見

Bashには、その後の構文解析に影響を与えるキーワードがいくつかあります[[しかしssh、それらの1つではなく、通常のコマンドです。この意味は:

  • ssh …通常全体ローカルシェルによって解析されます以下のような文字|;*"$またはスペース平均殻に何か、彼らはに取得することはできませんsshあなたは(一部の例外を除いて、例えば唯一のそれらを引用したり脱出しない限り、$別の単語としては特別なものではありません)。これは、構文解析と解釈の最初のレベルです。
  • sshシェルがその仕事をした後に引数(または他の通常のコマンド)が何であれ、それらは単なる引数、文字列です。それらを解釈するのは今やツールの仕事です。これは第2レベルです。

sshコマンドライン引数一部(ゼロ、1つ以上)の場合、サーバー側で実行されるコマンドとして解釈されます。一般にssh、多くの引数からコマンドを作成できます。その効果は、サーバーで次のようなものを呼び出したかのようです。

"$SHELL" -c "$command_line_built_by_ssh"

これとまったく同じだとは言いませんが、何が起こるかを理解するのに十分近いです。シェルで呼び出されたかのように書いたので、見覚えがありますが、実際にはまだシェルがありません。いいえ$command_line…、変数としては、この回答の目的で文字列を参照するためにこの名前を使用しています。)

次に$SHELL、サーバー$command_line…上で独自に解析ますこれは第3レベルです。


特定の観察

失敗したコマンド

ssh -t [email protected] sudo docker exec -it `sudo docker ps | grep mycontainername | awk '{print $1;}'` env

123.456.789.10 有効なIPアドレスではないため、失敗しました

OK、123.456.789.10プレースホルダーだと理解していますが、それでも有効ではありません。:)

コマンドはsudo docker ps | grep mycontainername | awk '{print $1;}'ローカルで実行さたため失敗しました出力はおそらく空でした。その後$command_line_built_by_ssh、あなたが望んでいたものからはほど遠いものでした。

ローカルでssh … | grep mycontainername実行するgrepことに注意してください(これに気付いている場合と気付いていない場合があります)。


討論

リモートシェルがどのようになるかを制御するには$command_line_built_by_ssh、以前に発生した解析と解釈を理解し、予測し、首謀する必要があります。あなたはそう、あなたの地元のコマンドを作る必要があるローカルシェルとsshそれが正確になり、それを消化し$command_line…、リモート側で実行したいです。

結果がに到達する前に、実際にローカルシェルを拡張したり、何かを置き換えたりする場合は、非常に複雑になる可能性がありますssh必要な逐語的な文字列がすでにあるため、ケースはより単純です$command_line_built_by_ssh文字列は次のとおりです。

sudo docker exec -it $(sudo docker ps | grep mycontainername | awk '{print $1;}') env

ノート:

  • 私は$()、バックティックはなく、の形式でコマンド置換を使用しましたを好む理由$()があります
  • まったくわかりません。二重引用符で囲む必要があるdockerかどうかはわかりません$(…)一般的に、引用しないことはほとんどの場合悪いことです。置換によって複数の単語が返される(つまり、複数の行が入力されるawk)とどうなるかを自問してくださいこれは別の問題であり(この場合は問題がある場合)、この回答では取り上げません。

ローカルシェルによってすべてが展開/解釈されないように保護するには、展開\をトリガーできる、または解釈できるすべての文字を適切に引用またはエスケープする必要がありますこの場合引用$()|;{}'および(多分または必要に応じて)スペース。

私は、どのようにssh … some command機能するかという理由で、「多分、またはオプションでスペースを引用またはエスケープする」と言いましたサーバー上で実行されるコードとして解釈される2つ以上の引数が見つかった場合、それらを連結し、間に単一のスペースを追加します。これが$command_line_built_by_ssh構築方法です。リモートシェルのコードのように見えるスペースを引用もエスケープもしない場合、ローカルシェルは単語を分割するときにスペース(およびタブ)を消費し、スペースsshを追加します。タブまたは複数の連続するスペースがある場合、結果は希望どおりにならない場合があります。例えば:

ssh user@server echo a     b

ssh取得user@serverechoabリモートコマンドは次のようになりますecho a bし、echoそこになりますab印刷しますa b

次にこれ:

ssh user@server 'echo a     b'

sshを取得user@serverecho a bます。リモートコマンドは次のようになりますecho a bし、echoそこになりますab印刷しますa b

そして最後にこれ:

ssh user@server 'echo "a     b"'

sshを取得user@serverecho "a b"ます。リモートコマンドがありecho "a b"echoそこにがありますa b印刷しますa b

結論として、ローカルシェルのコンテキストで引用し、リモートシェルのコンテキストで個別引用する必要がありますシェルによって物事を拡張することになると、外側の引用符が重要になることに注意してください


解決

このすべての情報をまとめると(それでも、すべてをローカルシェルによって拡張/解釈されないように保護したい場合)、次のようにアドバイスします。

  • 引用または脱出。
  • 好む引用単一の間、引用符のシングルペアは、多くの文字を保護することができますので、エスケープの上に\一つだけの文字を保護します。ほとんどの場合、すべてを保護するために多くの円記号が必要になります。多くの場合、1組の引用符で同じ結果を得ることができます。
  • 優先単一引用符を')、彼らはしかし、すべてを保護することができます'一方、二重引用符(")を保護することができ'なく$"(また\時には、また!時にはバッシュで)、しない限り$、そのようなも同様にエスケープされている(つまり、エスケープ引用された、つまりは二重引用符でエスケープ;以外! である 面倒)。
  • コマンドを単一の引数として提供することをお勧めsshます。

これにより、次の手順が実行されます。

  1. リモート側で実行する逐語的なコマンドを準備します。
  2. すべて''"'"'またはで置き換え'\''ます(それぞれに個別に選択できます')。
  3. 結果の文字列全体を一重引用符で囲みます。
  4. ssh …前に追加します。

逐語的なコマンドは次のとおりです。

sudo docker exec -it $(sudo docker ps | grep mycontainername | awk '{print $1;}') env

手順の結果は次のとおりです。

ssh -t user@server 'sudo docker exec -it $(sudo docker ps | grep mycontainername | awk '\''{print $1;}'\'') env'
# single-quoted     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^    ^^^^^^^^^^^    ^^^^^
# escaped                                                                                ^              ^

この手順では、可能な限り短い文字列が得られない場合があることに注意してください。洞察があれば、文字列を「最適化」できる場合があります。しかし、手順は非常に簡単で、完全に信頼できます。ローカルシェルによってすべてが拡張/解釈されないように保護したいことがわかっている場合は、手順自体にそれ以上の洞察は必要ありません。


オートメーション

実際、手順は自動化できます。文字列に引用符を追加し、既存の引用符を適切に保持できるツールがあります。Bash自体はそのようなツールです。私のこの答えは、Bashのキーストロークでこれを行う方法を提供します。あなたのケースに合わせて調整できる可能な解決策は次のとおりです。

  1. ローカルシェルで、次のカスタム関数とバインディングを定義します。

    _prepend_ssh() { READLINE_LINE="ssh  ${READLINE_LINE@Q}"; READLINE_POINT=4; }
    bind -x '"\C-x\C-h":_prepend_ssh'
    
  2. ローカルシェルで、リモートシェルで実行するコマンドを入力(または貼り付け)します。実行しないでください。コマンドは、リモートシェルに配置したいものまったく同じである必要があります。

  3. ヒットCtrl+ xCtrl+ hローカルシェルが引用を処理します。またssh、前に追加し、直後にカーソルを置きます。
  4. 欠落している引数(例-t user@serverを追加(型)します便宜上、カーソルはすでにこれを行うのに適切な位置にあります。
  5. Enter

代替案

逐語的なコマンドをリモートシェルに渡す別の方法があります。場合によっては、を介してそれらをパイプできますsshリモートコマンドラインは次のようになっていると仮定しましょう。

echo "$PATH"; date

上記のように進め、一重引用符を追加して、次のようにローカルで実行できます。

ssh user@server 'echo "$PATH"; date'

例は単純ですが、一般的に引用符を追加するのは必ずしも簡単ではありません。または、次のようにコマンドをパイプすることもできechoます簡単にするために;printfより良い):

echo 'echo "$PATH"; date' | ssh user@server bash

それでもこれらの一重引用符が必要です。ただし、ファイルにコマンドがある場合は、次のようにします。

<file ssh user@server bash

または、ファイルがなくても(ヒアドキュメント):

ssh user@server bash <<'EOF'
echo "$PATH"
date
EOF

(の引用符はローカルで展開さ<<'EOF'ないように注意してください$PATH。)

利点:

  • 複数行のコマンド/スニペット/スクリプトを簡単に渡すことができます(echo … ; dateこれを示すために分割しました)。
  • 引用の追加レイヤーは必要ありません。
  • あなたは明示的にシェル(例である必要はありません遠隔通訳選択することができますbashzsh、またはをpython)。

短所:

  • リモートインタープリターを明示的に指定する必要があります。そうしないと、デフォルトのログインシェルが生成され、その日のメッセージが出力される可能性があります。適切に引用符で囲まれたものを指定することにより、デフォルトのシェルを非ログインシェルとして引き続き使用できますexec "$SHELL"(行は次のようになりますssh … 'exec "$SHELL"' <<'EOF')。
  • の標準入力はssh端末はないため、使用できません-t(これが、元のコマンドを例として使用しなかった理由です)。
  • コマンドはbash、標準入力を介してリモートインタープリター(例では)に到達します。考えられる問題:
    • 子プロセス(またはビルトイン)は同じstdinを使用します。それらのいずれかがそのstdinから読み取る場合、同じストリームを読み取ります。おそらく、インタープリター宛ての次のコマンドを読み取ります。この動作は抑制したり、創造的に(乱用)使用したりすることができますが、詳しくは説明しません。
    • このチャネルを使用して他のものを簡単にパイプすることはできません。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

Pythonで複雑なコマンドラインを実行する

分類Dev

Qtで複雑なLinuxコマンドを実行する方法は?

分類Dev

C#から複雑なコマンドラインを実行する

分類Dev

ノードjsスポーンで複雑なコマンドを実行する方法は?

分類Dev

コマンドをsshでラップする:複雑な引用符を管理する方法は?

分類Dev

Java で複雑なプロセス コマンドラインを実行する

分類Dev

ssh経由で複雑なコマンドを送信する

分類Dev

Pythonシェルでbashの複雑なfindコマンドを実行する

分類Dev

bashスクリプトで複雑なコマンドを実行する

分類Dev

SSHログインでコマンドを自動的に実行する方法は?

分類Dev

ssh-複雑なリモートコマンドを実行します

分類Dev

コマンドラインではなくブラウザでnodejsコードを実行する方法

分類Dev

SSHはコマンドを異なる方法で実行します

分類Dev

SSHはコマンドを異なる方法で実行します

分類Dev

コマンドラインでJuliaコードを実行する方法は?

分類Dev

コマンドラインから複雑なファイル構造を持つJavaプログラムをコンパイルして実行する

分類Dev

コマンドラインで AppImage を実行する方法

分類Dev

ssh上でバッチモードでコマンドを実行する方法は?

分類Dev

bashスクリプトから複雑なコマンドを実行する

分類Dev

異なるスイッチで複数のsshコマンドを実行する

分類Dev

Javaで多くの複雑なコマンドライン引数を解析する最良の方法は何ですか?

分類Dev

コマンドとherokuからメインクラスなしで.warを実行する方法は?

分類Dev

「サブプロセス」を使用して複雑なバッチコマンドを実行する方法

分類Dev

プログラムでAndroidでSSHコマンドを実行する方法

分類Dev

成功するまでsshコマンドを実行する方法は?

分類Dev

Bashで複数のコマンドをsshして実行する最もクリーンな方法は何ですか?

分類Dev

ラバでmongodbrunコマンドを実行する方法は?

分類Dev

複雑なパスワードをWindowsコマンドライン(シェル)に貼り付ける方法は?

分類Dev

Bashで複数のコマンドを実行する方法(一部はバックグラウンドで)

Related 関連記事

  1. 1

    Pythonで複雑なコマンドラインを実行する

  2. 2

    Qtで複雑なLinuxコマンドを実行する方法は?

  3. 3

    C#から複雑なコマンドラインを実行する

  4. 4

    ノードjsスポーンで複雑なコマンドを実行する方法は?

  5. 5

    コマンドをsshでラップする:複雑な引用符を管理する方法は?

  6. 6

    Java で複雑なプロセス コマンドラインを実行する

  7. 7

    ssh経由で複雑なコマンドを送信する

  8. 8

    Pythonシェルでbashの複雑なfindコマンドを実行する

  9. 9

    bashスクリプトで複雑なコマンドを実行する

  10. 10

    SSHログインでコマンドを自動的に実行する方法は?

  11. 11

    ssh-複雑なリモートコマンドを実行します

  12. 12

    コマンドラインではなくブラウザでnodejsコードを実行する方法

  13. 13

    SSHはコマンドを異なる方法で実行します

  14. 14

    SSHはコマンドを異なる方法で実行します

  15. 15

    コマンドラインでJuliaコードを実行する方法は?

  16. 16

    コマンドラインから複雑なファイル構造を持つJavaプログラムをコンパイルして実行する

  17. 17

    コマンドラインで AppImage を実行する方法

  18. 18

    ssh上でバッチモードでコマンドを実行する方法は?

  19. 19

    bashスクリプトから複雑なコマンドを実行する

  20. 20

    異なるスイッチで複数のsshコマンドを実行する

  21. 21

    Javaで多くの複雑なコマンドライン引数を解析する最良の方法は何ですか?

  22. 22

    コマンドとherokuからメインクラスなしで.warを実行する方法は?

  23. 23

    「サブプロセス」を使用して複雑なバッチコマンドを実行する方法

  24. 24

    プログラムでAndroidでSSHコマンドを実行する方法

  25. 25

    成功するまでsshコマンドを実行する方法は?

  26. 26

    Bashで複数のコマンドをsshして実行する最もクリーンな方法は何ですか?

  27. 27

    ラバでmongodbrunコマンドを実行する方法は?

  28. 28

    複雑なパスワードをWindowsコマンドライン(シェル)に貼り付ける方法は?

  29. 29

    Bashで複数のコマンドを実行する方法(一部はバックグラウンドで)

ホットタグ

アーカイブ