AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 772947
Accepted
Whimusical
Whimusical
Asked: 2024-03-23 08:19:58 +0800 CST2024-03-23 08:19:58 +0800 CST 2024-03-23 08:19:58 +0800 CST

Redirecionando stdout de um script como stdin de outro script/comando em execução em uma sessão tmux

  • 772

Estou adaptando a resposta de Marcus Müller a uma pergunta que fiz na semana passada - um script que redireciona seu stdout para uma sessão tmux para renderizar sequências de escape ANSI e, em seguida, captura a renderização do painel como a saída real do script. Eu sei que não é nada útil, já que você pode imprimi-lo diretamente no stdout e ter o mesmo resultado, mas é apenas uma demonstração para brincar, para trazer o código para um projeto maior e mais complexo de explicar, onde preciso desse recurso :

#!/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

quais saídas (e devem):

boo
bar

Estou interessado em simplificar o código. É possível usar algum truque que funcione com o redirecionamento stdin em vez de um fifo que precisa ser mantido? Posso usar uma linha de alguma forma que continue imprimindo tudo e feche a sessão automaticamente quando terminar?

Eu tentei e brinquei com tmux pipe-pane, buffer, send-keys e run-shell e não consegui. Principalmente quando a sessão leva stdin como se você tivesse escrito um comando no console, não como o stdin do script que um comando/script que está rodando

Eu sinto que deve ser simplificável de alguma forma.

zsh
  • 3 3 respostas
  • 73 Views

3 respostas

  • Voted
  1. Best Answer
    Kamil Maciorowski
    2024-03-25T02:55:23+08:002024-03-25T02:55:23+08:00

    É possível usar algum truque que funcione com o redirecionamento stdin em vez de um fifo que precisa ser mantido?

    Pergunte tmuxo que ttyestá atribuído ao único painel da única janela da nova sessão. Em seguida, imprima nele.

    #!/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
    

    Obter informações tmux display-message -pé bastante útil em geral. No seu caso, você pode obter informações sobre o tty diretamente em tmux new-session; e você não precisa da ttyvariável. Você pode configurar o redirecionamento sem etapas preliminares, como esta:

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

    Note tail -f /dev/nullé apenas um comando para manter o painel tmux "vivo". O script não tenta enviar nada para este comando; em vez disso, imprime no tty correto. Esta resposta não resolve o título ("Redirecionando stdout de um script como o stdin de outro script/comando em execução em uma sessão tmux"), mas fornece a funcionalidade desejada.

    • 2
  2. G-Man Says 'Reinstate Monica'
    2024-03-23T09:32:09+08:002024-03-23T09:32:09+08:00

    Não estou claro exatamente o que você está perguntando. Você está aceitando o conceito de usar o tmux para processar as sequências de escape, mas deseja apenas eliminar o FIFO?

    Tente apenas produzir a saída desejada em 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
    

    e deixe de lado o material FIFO.

    PS Você deve citar variáveis ​​​​do shell, como $fifoe  $tmpdir. Você realmente não precisa citar strings constantes compostas de caracteres que não sejam espaços em branco, como "aux".

    • 1
  3. Stéphane Chazelas
    2024-03-23T20:01:34+08:002024-03-23T20:01:34+08:00

    Eu não acho que você possa fazer algo assim, pois tmuxfechará todos os fds acima de 2 recebidos (e 0, 1, 2 também quando desconectados).

    Veja close_range(3, 4294967295, 0)ou equivalente na stracesaída (ou equivalente) ou nas closefrom(STDERR_FILENO + 1)chamadas na fonte.

    Portanto, você precisará passar os dados de alguma outra maneira, por meio de um canal nomeado como você faz ou de uma variável de ambiente (mas não pode conter caracteres NUL) ou incorporado no código shell executado por tmuxum soquete, arquivo temporário, memória compartilhada , nenhum dos quais será realmente mais simples ou confiável.

    Existem vários problemas em sua abordagem:

    • você está usando um nome de sessão fixo, o que significa que o script não pode ser usado de maneira confiável, a menos que você possa garantir que duas invocações dele não sejam executadas ao mesmo tempo. Você pode tmuxescolher o nome da sessão e recuperá-lo através da -Popção new-session.
    • você não faz nenhuma sincronização: quando você executa capture-pane, não há garantia de que catterá terminado ou mesmo iniciado. Você está fazendo esse loop + kill em vez de dizer à sessão do tmux para sair quando você recuperar o conteúdo do painel.
    • você está incorporando o conteúdo $fifodentro do código shell executado na nova sessão. Melhor passar como uma variável de ambiente.
    • você não está verificando o status de saída de mktempou mkfifo.
    • tmux irá ler o usuário, ~/.tmux.confo que pode interferir no processamento
    • você vai querer passar TERM=tmuxpara o ambiente de tput(ou equivalente interno do zsh echoti), pois é um tmuxemulador de terminal que acabará interpretando em vez do terminal host no qual você executa o script, então você precisa enviar as sequências de escape que ele prefere do que o terminal host entenderá¹.
    • com -S0 -E1, você está capturando apenas as duas primeiras linhas visíveis do painel
    • você poderia dizer ao tmux para criar um painel do mesmo tamanho da janela do terminal host
    • você também pode querer obter o conteúdo do buffer de rolagem, caso a saída não caiba em uma tela.

    Então, talvez algo como:

    #! /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
    

    Então, por exemplo:

    $ (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
    

    (observe todos os bytes 0x0a (LF), pois minha janela de terminal tem 60 linhas de altura).

    ( isenção de responsabilidade : eu não sou um usuário do tmux, então pode muito bem haver maneiras mais inteligentes ou corretas de fazer isso lá)


    ¹ Embora, no caso do homerecurso, seja improvável que faça diferença na prática, pois é improvável que você esteja usando um terminal para o qual a homesequência de escape seja diferente daquela da tmux'própria emulação ( \e[H).

    • 1

relate perguntas

  • Listar arquivos que não possuem outro arquivo com sufixo

  • Em que circunstâncias o executável encontrado primeiro no caminho não será usado

  • Symlinking para todos os arquivos de ponto e diretórios

  • Como incrementar uma variável nomeada dinamicamente em `zsh`

  • Por que não consigo definir uma variável somente leitura chamada path no zsh?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve