적응 중이에요마커스 뮐러의 답변 지난 주에 질문을 했습니다. 표준 출력을 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 리디렉션과 관련된 트릭이 있습니까? 한 줄짜리 방법을 사용하여 모든 내용을 계속 인쇄하고 완료되면 세션을 자동으로 닫을 수 있습니까?
tmux 파이프 창, 버퍼, 전송 키 및 실행 쉘을 사용해 보았지만 작동하지 못했습니다. 특히 명령/스크립트를 실행하는 스크립트의 stdin이 아닌 콘솔에 명령을 작성하는 것처럼 세션이 stdin을 사용하는 경우
어떻게든 단순화해야 할 것 같은 느낌이 듭니다.
답변1
유지 관리해야 하는 FIFO 대신 사용할 수 있는 stdin 리디렉션과 관련된 트릭이 있습니까?
새 세션에 할당된 고유 창의 고유 창 내용을 묻습니다 tmux
. tty
그런 다음 인쇄하십시오.
#!/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/null
tmux 창을 "활성"으로 유지하는 명령일 뿐입니다. 스크립트는 명령에 아무 것도 보내려고 시도하지 않지만 올바른 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의 내용을 무시합니다.
$fifo
PS 및 와 같은 쉘 변수를 인용해야 합니다 $tmpdir
. 공백이 아닌 문자로 구성된 상수 문자열을 실제로 인용할 필요는 없습니다 "aux"
.
답변3
나는 당신이 그런 일을 할 수 없다고 생각합니다. tmux
그렇게 하면 2(그리고 분리될 때 0, 1, 2) 이상으로 수신하는 모든 fd가 닫히기 때문입니다.
close_range(3, 4294967295, 0)
출력에서 동등한 항목을 확인 하거나 소스에서 호출하세요.strace
closefrom(STDERR_FILENO + 1)
따라서 명명된 파이프나 환경 변수(NUL 문자는 포함하지 않음)를 통해 또는 소켓, 임시 파일, 공유 메모리에 의해 실행되는 셸 코드에 포함된 다른 방법으로 데이터를 전달해야 합니다. tmux
둘 중 어느 것도 사실이 아닙니다. 더 간단하거나 더 안정적일 것입니다.
그러나 귀하의 접근 방식에는 많은 문제가 있습니다.
- 고정된 세션 이름을 사용하고 있습니다. 이는 스크립트에 대한 두 호출이 동시에 실행되지 않는다는 것을 보장할 수 없으면 스크립트를 안정적으로 사용할 수 없음을 의미합니다. 세션 이름을 선택하고
tmux
옵션을 통해-P
검색 할 수 있습니다new-session
. - 동기화는 수행하지 않습니다. 실행하면 완료되거나 시작된다는
capture-pane
보장이 없습니다cat
. 창의 내용을 검색하면 tmux 세션을 종료하라고 지시하는 대신 루프 + 종료를 수행하게 됩니다. $fifo
새 세션에서 실행되는 셸 코드에 콘텐츠를 포함시킵니다. 환경 변수로 전달되는 것이 가장 좋습니다.mktemp
의 종료 상태를 확인하지 않았습니다mkfifo
.- tmux는 사용자의 데이터를 읽습니다
~/.tmux.conf
. 이는 처리를 방해할 수 있습니다. - 이것은 스크립트를 실행하는 호스트 터미널이 아니라 최종적으로 해석되는 터미널 에뮬레이터이기 때문에
TERM=tmux
환경tput
(또는 zsh의 내장 동등 항목)으로 전달해야 하므로 이스케이프 시퀀스를 보내야 합니다.echoti
tmux
그것오히려 호스트 터미널이 이해합니다. - 를 사용하면
-S0 -E1
창의 처음 2개 표시 행만 캡처됩니다. - 호스트 터미널 창과 동일한 크기의 창을 생성하도록 tmux에 지시할 수 있습니다.
- 출력이 한 화면에 맞지 않는 경우 스크롤백 버퍼의 내용을 가져올 수도 있습니다.
아마도 다음과 같을 것입니다.
#! /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
사용할 가능성이 없기 때문에 실제로 영향을 미칠 가능성은 거의 없습니다 .home
tmux
\e[H