Construa um comando colocando uma string em um tty

13

Eu consegui fazer isso

echo -n "command" > /dev/tty1

As letras aparecem, e o cursor se move, mas elas são "fantasmas" - se você pressionar Enter , nada acontece (elas não estão em stdin).

Editar:

No meio da captura de tela abaixo, você vê porque vejo o uso disso. (A linha com uma legenda vermelha, logo abaixo da linha com uma legenda amarela.) Como está agora, você não está realmente "editando" o texto da nota; você é solicitado a escrever um novo texto, que substituirá o texto da nota que você está (não realmente) editando. Assim, achei que poderia ser solucionado simplesmente colando o texto antigo no tty: se o usuário pressionar enter, nenhuma modificação será feita. (Este programa está em Perl / MySQL, mas achei que seria mais interessante pedir uma solução geral do que "como faço isso em Perl".)

Editar2:

AquiestáocódigoPerl,queusaocódigoCabaixo(funcionaexatamentecomoplanejado),bemcomoumanovacapturadetela-esperoqueissoesclareçaascoisassemsombradedúvida:)Novamente,olheparaomeiodacapturadetela,ondeAediçãoéfeitaparaotextodanota-destavez,otextoantigoestálá,porexemplo,sevocêquiserapenascorrigirumerrodedigitação,vocênãoteráquedigitarnovamentetodootextodanota.

my$edit_note_text=$edit_note_data[2];printBOLD,RED," new text: ", RESET;
system("writevt /dev/tty \"$edit_note_text\"");
my $new_text = <$in>;
$new_text = fix_input($new_text);
my $set_text = "UPDATE notes SET note = \"$new_text\" WHERE id = $edit_note_id";
$db->do($set_text);

    
por Emanuel Berg 13.09.2012 / 23:37

4 respostas

3

Acabei de encontrar um pequeno programa em C chamado writevt que faz o truque. Pegue o código-fonte aqui . Para compilar com gcc , basta remover as seguintes linhas primeiro:

#include <lct/cline.h>
#include <lct/utils.h>

Atualizar . O comando é agora parte de console-tools , portanto disponível em sistemas mais recentes, a menos que sua distribuição use kbd ao invés de console-tools , em Nesse caso, você pode compilar a partir da fonte (versão muito mais recente, nenhuma modificação necessária) .

Uso:

sudo writevt /dev/ttyN command 

Observe que, por algum motivo, você precisa usar '\r' (ou '\x0D' ) em vez de '\n' (ou '\x0A' ) para enviar um retorno.

    
por 14.09.2012 / 00:34
8

Um terminal funciona como duas coisas: um dispositivo de entrada (como um teclado) e um dispositivo de exibição (como um monitor). Quando você lê a partir do terminal, você obtém o que vem do dispositivo de entrada. Quando você escreve no terminal, os dados vão para o dispositivo de exibição.

Não existe uma maneira geral de forçar a entrada em um terminal. Raramente há necessidade de fazer isso. Se você precisar interagir com um programa que exija um terminal, use um emulador de terminal dedicado, como Expecto ou Empty ou um wrapper de terminal programável como Tela ou Tmux . Você pode forçar a entrada em um console do Linux com um ioctl . Você pode forçar a entrada em um emulador de terminal X11 com ferramentas como xdotool ou xmacro .

    
por 14.09.2012 / 03:16
7

Pelo menos Linux e BSDs possuem o TIOCSTI ioctl para empurrar os caracteres de volta para o buffer de entrada de terminal (até um limite de [4096 caracteres no Linux]):

#include <sys/ioctl.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>

void stackchar(char c)
{
  if (ioctl(0, TIOCSTI, &c) < 0) {
    perror("ioctl");
    exit(1);
  }
}
int main(int argc, char *argv[])
{
  int i, j;
  char c;

  for (i = 1; i < argc; i++) {
    if (i > 1) stackchar(' ');
    for (j=0; (c = argv[i][j]); j++) {
      stackchar(c);
    }
  }
  exit(0);
}

Compile e chame como:

cmd foo bar < "$some_tty"

para empurrar caracteres de volta em algum tty.

E em perl:

require "sys/ioctl.ph";
ioctl(STDIN, &TIOCSTI, $_) for split "", join " ", @ARGV;

Editar : percebo agora que é o mesmo ioctl que na solução writevt . O comentário e o nome do comando são enganosos, pois o TIOCSTI funciona para qualquer terminal, não apenas VTs.

    
por 14.09.2012 / 23:47
0

Eu tenho uma demonstração mais completa no Stack Overflow .

Em python você pode fazer:

import fcntl
import sys
import termios

with open('/dev/tty1', 'w') as fd:
    for char in "ls -la\n":
        fcntl.ioctl(fd, termios.TIOCSTI, char)

Isso pressupõe um valor simples de "command" de ls -la e o uso do caminho tty especificado por OP.

    
por 16.02.2017 / 21:40

Tags