スクリプトの標準出力をtmuxセッションで実行される他のスクリプト/コマンドの標準入力にリダイレクトする

スクリプトの標準出力をtmuxセッションで実行される他のスクリプト/コマンドの標準入力にリダイレクトする

適応中です。マーカス・ミュラーの答え 先週質問しました。標準出力をtmuxセッションにリダイレクトしてANSIエスケープシーケンスをレンダリングし、ウィンドウレンダリングをスクリプトの実際の出力にキャプチャするスクリプト。 stdoutで直接印刷して同じ結果を得ることができるので、まったく役に立たないことを知っています。ただし、これはより複雑な解釈を通じてコードをより大きなプロジェクトにインポートするためのデモであり、次の機能が必要です。

#!/bin/zsh

tmpdir="$(mktemp -d)"
fifo="${tmpdir}/fifo"
mkfifo "$fifo"
tmux new-session -d -s aux "while true; do cat ${fifo}; done"

exec 3>&1 1>"$fifo"


echo foo
echo bar
tput home
echo -n b

exec 1>&3 3>&-

tmux capture-pane -t "aux" -p -S0 -E1
tmux kill-session -t aux
rm -rf $tmpdir

出力は次のようになります(そしてそれが必要です)。

boo
bar

コードの簡素化に興味があります。メンテナンスが必要なFIFOの代わりに使用できるstdinリダイレクトに関連するトリックはありますか? 1行の方法ですべてのコンテンツを印刷し続け、完了したらセッションを自動的に閉じることができますか?

tmuxパイプウィンドウ、バッファ、トランスポートキー、実行シェルを試しましたが、うまくいきませんでした。特に、コマンド/スクリプトを実行するスクリプトのstdinではなく、コンソールにコマンドを作成するのと同じように、セッションがstdinを使用する場合

なんとか単純化しなければならないような感じがします。

答え1

メンテナンスが必要なFIFOの代わりに使用できるstdinリダイレクトに関連するトリックはありますか?

新しいセッションに割り当てられたユニークウィンドウのユニークウィンドウの内容を尋ねますtmuxttyその後、印刷します。

#!/bin/zsh

tmux new-session -d -s aux 'tail -f /dev/null' || exit 1
tty="$(tmux display-message -p -t aux -F '#{pane_tty}')"

{
  echo foo
  echo bar
  TERM=tmux tput home
  echo -n b
} > "$tty"

tmux capture-pane -t aux -p -S0 -E1
tmux kill-session -t aux

tmux display-message -p一般的に言えば、それから情報を得ることは非常に便利です。あなたの場合はttyに関する情報を直接得ることができ、tmux new-sessionその変数は必要ありませんtty。リダイレクトを設定するために、次の準備手順を実行する必要はありません。

{...} >"$(tmux new-session -d -s aux -P -F '#{pane_tty}' 'tail -f /dev/null')" || exit

注はtail -f /dev/nulltmuxウィンドウを「アクティブ」に保つためのコマンドです。スクリプトはコマンドに何も送信しようとしませんが、正しいttyに印刷します。この回答は、タイトル(「tmuxセッション内で実行される他のスクリプト/コマンドの標準入力へのスクリプトの標準出力リダイレクト」)には対応していませんが、必要な機能を提供します。

答え2

正確に何を求めるのかよくわかりません。エスケープシーケンスを処理するためにtmuxを使用するという概念を受け入れますが、ただFIFOを削除したいですか?

必要な結果のみを作成してくださいtmuxから:

tmux new-session -d -s aux "echo foo; echo bar; tput home; echo -n b"

tmux capture-pane -t aux -p -S0 -E1
tmux kill-session -t aux

FIFOの内容を無視します。

$fifoPSなどのシェル変数を引用する必要があります$tmpdir。空白以外の文字で構成される定数文字列を実際に引用する必要はありません"aux"

答え3

そんなことができないと思います。tmuxこれは、2(そして分離されたときに0、1、2)以上で受信されたすべてのfdが閉じられるためです。

close_range(3, 4294967295, 0)出力で同等の項目を確認するか、ソースから呼び出してください。straceclosefrom(STDERR_FILENO + 1)

したがって、名前付きパイプまたは環境変数(NUL文字を含まない)を介して、またはソケット、一時ファイル、共有メモリによって実行されるシェルコードに含まれる他の方法でデータを渡す必要があります。tmuxどちらも真実ではありません。より簡単またはより安定しています。

しかし、あなたのアプローチには多くの問題があります。

  • 固定セッション名を使用しています。これは、スクリプトへの2つの呼び出しが同時に実行されないことを保証できない場合、スクリプトを確実に使用できないことを意味します。セッション名を選択してtmuxオプションで-P検索できますnew-session
  • 同期は行いません。実行すると完了または開始されるcapture-pane保証はありませんcat。ウィンドウの内容を検索すると、tmuxセッションを終了するように指示するのではなく、ループ+シャットダウンを実行します。
  • $fifo新しいセッションで実行されるシェルコードにコンテンツを含めます。環境変数として渡されるのが最善です。
  • mktempの終了ステータスを確認していませんmkfifo
  • tmuxはユーザーのデータを読み取ります~/.tmux.conf。これは処理を妨げる可能性があります。
  • これはスクリプトを実行するホスト端末ではなく最終的に解釈される端末エミュレータであるため、TERM=tmux環境tput(またはzshの組み込み同等項目)に渡す必要があるため、エスケープシーケンスを送信する必要があります。echotitmuxそれむしろホスト端末が理解している。
  • を使用すると、-S0 -E1ウィンドウの最初の2つの表示行のみがキャプチャされます。
  • ホスト端末ウィンドウと同じサイズのウィンドウを作成するようにtmuxに指示できます。
  • 出力が1つの画面に収まらない場合は、スクロールバックバッファの内容を取得することもできます。

おそらく次のようになります。

#! /bin/zsh -

tmpdir=$(mktemp -d) || exit
trap 'rm -rf -- $tmpdir' EXIT INT TERM HUP QUIT

in=$tmpdir/in out=$tmpdir/out
mkfifo -- $in $out || exit
session=$(
  IN=$in OUT=$out tmux -f /dev/null new-session -PEd -x ${COLUMNS:-80} -y ${LINES:-24} '
    cat -- "$IN"
    echo done > "$OUT"
    read may_I_exit < "$IN"
    '
) || exit

cat "$@" > $in || exit

read can_I_retrieve_the_output < $out || exit
tmux capture-pane -t $session -pS-
echo you may exit > $in

たとえば、次のようになります。

$ (TERM=tmux; print -rln foo bar$terminfo[home]b) | ./capture | hexdump -C
00000000  62 6f 6f 0a 62 61 72 0a  0a 0a 0a 0a 0a 0a 0a 0a  |boo.bar.........|
00000010  0a 0a 0a 0a 0a 0a 0a 0a  0a 0a 0a 0a 0a 0a 0a 0a  |................|
*
00000040  0a 0a                                             |..|
00000042

(マイターミナルウィンドウの高さは60行なので、すべて0x0a(LF)バイトに注意してください。)

婦人声明:私はtmuxユーザーではないので、これを行うよりスマートで正確な方法があります。)


1この機能に関する限り、自己エミュレーション()と他のエスケープシーケンスを持つ端末をhome使用する可能性がないため、実際に影響を与える可能性はほとんどありません。hometmux\e[H

関連情報