Saídas diferentes para diferentes terminais no Ubuntu

1

Estou desenvolvendo um aplicativo C ++, no Ubuntu, e preciso transmitir as saídas para vários terminais. Eu preciso fazer isso programaticamente, chamando (por exemplo) comandos bash do aplicativo C ++ e direcionando a saída para o terminal correspondente. E eu não posso instalar qualquer ferramenta já desenvolvida "multi-terminal" (como "terminator", ou outros); em vez disso, preciso usar comandos bash padrão.
Então:

process A -> will show its output in terminal A.
process B -> will show its output in terminal B.
process C -> will show its output in terminal C.

Note, então:

  • Eu estarei transmitindo para vários terminais simultaneamente, informações diferentes e informações específicas para um terminal específico.
  • Você já viu o aircrack funcionando? Eu me lembrei daquele aplicativo mostrando três terminais diferentes ao mesmo tempo, cada um posicionado em coordenadas x, y específicas da tela, e cada um deles mostrando informações diferentes. Bem, acho que é disso que preciso.
  • Navegação, encontrei o seguinte comando "gnome-terminal" e adaptei-o para executar 3 terminais:

    gnome-terminal --geometry=45x20+10+10; gnome-terminal --geometry=45x20+505+10; gnome-terminal --geometry=45x20+950+10
    

Alguns detalhes:

  • os terminais não precisam ser do gnome. Eles podem ser apenas consoles simples, xterms; o que o Ubuntu fornece por padrão.
  • Eu não preciso iniciar os três terminais de uma só vez (como o exemplo de comando acima). Mas, quando o processo correspondente precisa ser transmitido para o seu terminal, o terminal deve estar aberto.
  • Como o programa saberá para qual terminal transmitirá a saída? Pode estar usando o pid do terminal? Se afirmativo, tendo o terminal pid, como eu estaria redirecionando a saída para aquele terminal?
  • Eu estava tentando obter o pid de cada terminal; por exemplo, assim:

    gnome-terminal --geometry=45x20+10+10 &
    

e procurando alguma maneira de redirecionar o pid para uma variável (não encontrar ainda ...).

    
por Karol Baum 04.06.2016 / 05:05

3 respostas

2

As sessões Unix são tratadas pelo TTY, que deve ser o seu ponto de partida. Se você usar a mesma conta de usuário para todas as sessões, deverá enviar a saída diretamente para o TTY que deseja.

Assim, você simplesmente teria que chamar seu programa com os diferentes TTYs que deseja usar na saída e seria capaz de abri-los para saída. Eu tentei no Gentoo e Centos sem nenhum problema.

Para encontrar o TTY de uma sessão, use o comando tty .

Outra opção que prefiro porque tem menos implicações de segurança ao lidar com outros usuários é fazê-lo em uma abordagem cliente-servidor em que os terminais do cliente se conectariam ao processo do servidor. Isso pode ser tão simples quanto usar pipes nomeados para cada um dos três terminais de saída.

    
por 04.06.2016 / 06:17
0

Se você simplesmente abrir um emulador de terminal e enviar alguns dados para ele, deverá estar ciente de que o shell padrão do usuário (provavelmente bash ) também estará sendo executado lá. Isso tem algumas consequências que provavelmente são indesejadas no seu caso de uso. A primeira coluna da saída ficará desalinhada devido ao prompt (a menos que você cuide de limpar a tela). Quaisquer que sejam os tipos de usuários que atrapalhem a tela, e mais importante, serão executados como um comando shell, o que é especialmente enganoso, já que o usuário provavelmente não vê mais o prompt lá. Além disso, se você também quiser ler a partir do terminal, você não seria capaz de fazer isso de forma confiável (para cada pressionamento de tecla será aleatório se ele chegar ao shell ou ao aplicativo.

Se eu entendi o contexto da sua pergunta corretamente, isso é indesejável para você. Os terminais abertos devem ser usados apenas para exibir a saída do seu aplicativo, e eles não devem executar um shell no meio-tempo. Como tal, você terá que especificar um comando personalizado para iniciar, em vez do shell padrão. Este comando customizado poderia facilmente ser um script simples (ou utilitário C ++) que envia o número da linha do terminal (a saída do comando tty ) de volta ao seu aplicativo, talvez altere algumas configurações de terminal e sinal (por exemplo, desligue o eco localstty), desabilite os sinais ( stty ou trap )) e, finalmente, insira um sleep gigante.

Pode haver muitas maneiras de enviar de volta o número tty para seu aplicativo principal. Esteja ciente de que o acionamento desses terminais e o script dentro dele são assíncronos do ponto de vista do seu aplicativo. Por exemplo. Se você colocar a saída de tty em um arquivo temporário com um nome de arquivo fixo, será necessário garantir que o aplicativo não leia prematuramente a versão anterior desse arquivo. Você pode, por exemplo crie um nome de arquivo aleatório exclusivo a cada vez e espere no aplicativo principal para que ele apareça.

Deixe-me recomendar-lhe uma abordagem completamente diferente a considerar.

gnome-terminal's (e a maioria (se não todos) outros emuladores de terminais baseados em Gtk +) a emulação de terminal real é feita pelo widget VTE. Se você escrever um aplicativo usando o kit de ferramentas Gtk +, adicionar um widget VTE é tão simples quanto adicionar, digamos, uma caixa de seleção.

Em vez de usar gnome-terminal ou xterm ou qualquer outra coisa, o próprio aplicativo pode apresentar uma janela gráfica contendo vários widgets VTE ou várias janelas gráficas com um único VTE dentro de cada um, o que você preferir. Ou se você não quiser ter a dependência Gtk + em seu aplicativo real, você pode facilmente criar um minúsculo aplicativo auxiliar separado para essa tarefa (você pode até considerar o Python em vez de C / C ++).

Neste caso, não há shell lançado por padrão (você teria que explicitamente fazer isso com o método vte_terminal_spawn_sync() , o qual você ficará feliz em não fazer). Você pode simplesmente pegar a linha do terminal com vte_pty_get_fd() , convertê-la em uma string com ptsname() e repassá-la para o seu aplicativo principal. Ou, se você fizer isso em um único aplicativo, talvez até vte_terminal_feed() os dados sejam exibidos.

    
por 05.06.2016 / 08:41
0

O problema deve ser simples: obtenha uma listagem de w ou who , que fornece nomes de usuários e nomes de terminal, como este:

$ w
 19:34:00 up  7:17,  5 users,  load average: 0.14, 0.08, 0.06
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
tom      pts/1    michener:S.0     14:07    3:21m 15.16s 15.08s vile /tmp/foo
tom      pts/4    michener:S.1     12:34    2.00s  0.22s  0.00s w
tom      pts/5    michener:S.2     13:00    9:48   3.13s  2.79s vile /usr/build
thomas   :0                        19:32   ?xdm?  47.31s  0.34s fvwm2 -f /usr/b
thomas   pts/3    :0               19:33    7.00s  0.04s  0.04s bash
$ who
tom      pts/1        2016-06-04 14:07 (michener:S.0)
tom      pts/4        2016-06-04 12:34 (michener:S.1)
tom      pts/5        2016-06-04 13:00 (michener:S.2)
thomas   :0           2016-06-04 19:32
thomas   pts/3        2016-06-04 19:33 (:0)

No entanto, nem todos os terminais têm suporte de trabalho para o utmp (onde essas informações são armazenadas). Se você se limitar ao Linux, poderá obter algumas informações úteis em /dev/pts , ou seja, os dispositivos com informações de propriedade:

$ ls -l /dev/pts
total 0
crw--w---- 1 tom    tty  136, 0 Jun  4 19:34 0
crw--w---- 1 tom    tty  136, 1 Jun  4 16:12 1
crw--w---- 1 thomas tty  136, 2 Jun  4 19:33 2
crw--w---- 1 thomas tty  136, 3 Jun  4 19:33 3
crw--w---- 1 tom    tty  136, 4 Jun  4 19:34 4
crw--w---- 1 tom    tty  136, 5 Jun  4 19:24 5
c--------- 1 root   root   5, 2 Jun  4 12:16 ptmx

Um script pode facilmente inspecioná-los, determinar quais são os usuários pretendidos e gravar nesses dispositivos (terminais).

Notas:

  • Com relação a "Como o programa saberá a qual terminal transmitirá a saída?", a abordagem usual usada é executar um cliente em cada um dos terminais que você deseja distinguir, fazendo com que eles se comuniquem com seu servidor são.

  • Um comentário perguntou como o programa saberá onde os clientes estão na tela. Você pode obter isso usando as propriedades da janela, por exemplo, começando com um id de janela e usando xwininfo . Existem diferenças entre tipos de emulador de terminal e qual id de janela é apropriado (ou utilizável). Mas a variável de ambiente WINDOWID em cada terminal é a maneira usual de obter essas informações (através do cliente que parece ser necessário, se você não quer simplesmente transmitir). Aqui está um exemplo de saída usando essa abordagem:

    xwininfo: Window id: 0x400023 "[!xwininfo] - vile"

      Absolute upper-left X:  0
      Absolute upper-left Y:  23
      Relative upper-left X:  0
      Relative upper-left Y:  22
      Width: 486
      Height: 551
      Depth: 24
      Visual: 0x22
      Visual Class: TrueColor
      Border width: 0
      Class: InputOutput
      Colormap: 0x21 (installed)
      Bit Gravity State: NorthWestGravity
      Window Gravity State: NorthWestGravity
      Backing Store State: NotUseful
      Save Under State: no
      Map State: IsViewable
      Override Redirect State: no
      Corners:  +0+23  -794+23  -794-428  +0-428
      -geometry 80x40+0+1

Leitura adicional:

por 05.06.2016 / 01:41

Tags