カールの出力をsshコマンドにパイプまたはリダイレクトします。

カールの出力をsshコマンドにパイプまたはリダイレクトします。

私はこれは不可能だと確信していますが、過去には間違っていました。

基本的に私が望むのは、カールコマンドのJSON出力を取得し、jqにパイプしてきれいに保つことです。良い結果。ただし、OSXにはこの機能がないため、Brewや他の方法でインストールする必要があります。私にとっては問題ではありません。しかし、企業環境では、サードパーティ製のアプリケーションをインストールすることが眉をひきます。しかし、多くのLinuxサーバーにはjqがインストールされています。

jqを実行するためにローカル出力をsshにパイプすることはできますか?

curl https://whatever.site/json | ssh linuxHost "jq '.'" > output.json

多数のLinuxサーバーには外部アクセス権がないため、そこからカールコマンドを実行しても機能しないことに注意してください。はい、scpを作成できますが、より多くのステップがあります。

答え1

やりたいことがすべてだったら美しい印刷JSONドキュメント(詳細フィルタリング、集計、またはその他の項目を除く)を使用すると、macOS基本システムユーティリティのより簡単なユーティリティjson_pp()を使用できます。/usr/bin/json_ppこのjson_ppユーティリティはPerlモジュール用のコマンドラインラッパーですJSON::PP

$ echo '{ "hello": "world!" }' | json_pp
{
   "hello" : "world!"
}

man json_ppカスタム出力形式(-json_optオプション)の説明については、参考資料を参照してください。

例:

$ echo '{ "hello": "world!" }' | json_pp -json_opt pretty,indent_length=2,space_before=0
{
  "hello": "world!"
}

答え2

はい、sshコマンドを実行している場合は、モードの代わりに仮想端末のリモートsshシステムでユーザーログインシェルを実行するのではなく、3つの異なるパイプラインに接続されているstdin、stdout、およびstderrを使用して指定されたコマンドを実行します。rshrloginsshd

これらのパイプの内容は暗号化されたトンネルを介して送信され、プロセスのstdin、stdout、およびstderrによって読み書きされますssh

だから:

local-cmd | ssh 'remote-cmd' > file
  • sshstdinはlocal-cmd書き込まれるパイプを読むことです。
  • ssh標準出力はfile書き込み専用モードで開きます。
  • ssh端末で実行している場合、stderrはおそらく端末装置です。

そして

  • 標準入力の読み取り値はssh暗号化されたチャネルを介して送信され、remote-cmd入力にパイプされます。
  • 標準出力のパイプに書き込まれた内容は、暗号化されたremote-cmdチャネルを介して送信されsshd(そのパイプのもう一方の端から読み取られ)、ssh受信時に標準出力に書き込まれます。つまり、ファイルに書き込まれます。
  • remote-cmd別のパイプで stderr と同じです。

lsofを使用してこれを観察できます。

$ sleep 3 | ((sleep 1; lsof -wc ssh -ad 0-99 +E >&2) <&- & ssh [email protected] 'lsof -wp "$$" -ad 0-2 +E; sleep 2') > file
COMMAND   PID     USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
screen   7561 chazelas    9u   CHR    5,2      0t0      89 /dev/ptmx ->/dev/pts/5 63562,zsh,0u 63562,zsh,1u 63562,zsh,2u 63562,zsh,10u 63608,sleep,0u 63608,sleep,2u 63609,ssh,2u 63609,ssh,6u 63610,lsof,1u 63610,lsof,2u
sleep   63608 chazelas    1w  FIFO   0,14      0t0  698683 pipe 63609,ssh,0r 63609,ssh,4r
ssh     63609 chazelas    0r  FIFO   0,14      0t0  698683 pipe 63608,sleep,1w 63609,ssh,4r
ssh     63609 chazelas    1u   CHR    1,3      0t0       5 /dev/null
ssh     63609 chazelas    2u   CHR  136,5      0t0       8 /dev/pts/5 7561,screen,9u
ssh     63609 chazelas    3u  IPv4 697921      0t0     TCP localhost:50006->localhost:ssh (ESTABLISHED)
ssh     63609 chazelas    4r  FIFO   0,14      0t0  698683 pipe 63608,sleep,1w 63609,ssh,0r
ssh     63609 chazelas    5w   REG   0,39      540 8488375 /home/chazelas/file
ssh     63609 chazelas    6u   CHR  136,5      0t0       8 /dev/pts/5 7561,screen,9u
~$ cat file
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
sshd    63612 root    5w  FIFO   0,14      0t0 698269 pipe 63692,bash,0r 63695,lsof,0r
sshd    63612 root    7r  FIFO   0,14      0t0 698270 pipe 63692,bash,1w 63695,lsof,1w
sshd    63612 root   10r  FIFO   0,14      0t0 698271 pipe 63692,bash,2w 63695,lsof,2w
bash    63692 root    0r  FIFO   0,14      0t0 698269 pipe 63612,sshd,5w
bash    63692 root    1w  FIFO   0,14      0t0 698270 pipe 63612,sshd,7r
bash    63692 root    2w  FIFO   0,14      0t0 698271 pipe 63612,sshd,10r

sshfds 4と5(fds 0と1からコピーされています)がそれぞれスリープモードでパイプに入るのがわかりますfile。あります。パイプはすべて。lsoffilesshd

したがって、このように実行は標準IOの場合はssh cmdローカル実行と機能的に似ていますcmdが、まだ注目すべき点がいくつかあります。

  • 上記のように、cmdリモートシステムのstdin / stdout / stderrは、クライアントの目的ssh(たとえば、この例ではそれぞれパイプ、通常のファイル、およびttyデバイス)に関係なく、すべてパイプです。たとえば、にリダイレクトしないと、出力がttyデバイスに移動したときにのみ色が割り当てられるため、出力に色が割り当てられていないことがfileわかります。jqjq
  • sshリモートホストから読み取られたかどうかにかかわらず、stdinから出力を消費してsshdに送信します。cmdたとえば、リモートコマンドが1行だけ読み取ったにもかかわらず、toの出力全体が送信されたため、seq 1000 | (ssh localhost 'IFS= read -r one_line_only'; cat)何も出力されません(ほとんどの理由は読まれません)。readsshseqsshdreadcat

ここでも次のことができます。

curl... | ssh 'jq . > remotefile'

リモート出力はjqリモートファイル(リモートユーザーのホームディレクトリ)に保存されます。または:

curl... | ssh 'jq . | tee remotefile' > localfile

(または単にcurl | ssh 'jq >&1 > remotefile' > localfileリモートユーザーのログインシェルがzshの場合)、出力はローカルjqおよびリモートで保存されます。


少なくともopensshの場合stdinとstdoutは異なるfdで繰り返されます。何かが使われており、標準出力は次回再開されます。/dev/nullしかし、これは実装の詳細であり、実際には違いはありません。

関連情報