私はこれは不可能だと確信していますが、過去には間違っていました。
基本的に私が望むのは、カールコマンドの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を使用して指定されたコマンドを実行します。rsh
rlogin
sshd
これらのパイプの内容は暗号化されたトンネルを介して送信され、プロセスのstdin、stdout、およびstderrによって読み書きされますssh
。
だから:
local-cmd | ssh 'remote-cmd' > file
ssh
stdinは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
ssh
fds 4と5(fds 0と1からコピーされています)がそれぞれスリープモードでパイプに入るのがわかりますfile
。あります。パイプはすべて。lsof
file
sshd
したがって、このように実行は標準IOの場合はssh cmd
ローカル実行と機能的に似ていますcmd
が、まだ注目すべき点がいくつかあります。
- 上記のように、
cmd
リモートシステムのstdin / stdout / stderrは、クライアントの目的ssh
(たとえば、この例ではそれぞれパイプ、通常のファイル、およびttyデバイス)に関係なく、すべてパイプです。たとえば、にリダイレクトしないと、出力がttyデバイスに移動したときにのみ色が割り当てられるため、出力に色が割り当てられていないことがfile
わかります。jq
jq
ssh
リモートホストから読み取られたかどうかにかかわらず、stdinから出力を消費してsshdに送信します。cmd
たとえば、リモートコマンドが1行だけ読み取ったにもかかわらず、toの出力全体が送信されたため、seq 1000 | (ssh localhost 'IFS= read -r one_line_only'; cat)
何も出力されません(ほとんどの理由は読まれません)。read
ssh
seq
sshd
read
cat
ここでも次のことができます。
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
しかし、これは実装の詳細であり、実際には違いはありません。