Costruisci un comando inserendo una stringa in un tty


15

Sono riuscito a farlo

echo -n " command "> / dev / tty1

Vengono visualizzate le lettere e il cursore si sposta, ma sono "fantasmi" - se colpisci Enter, non succede nulla (non sono nello stdin).

Modificare:

Nel mezzo dello screenshot qui sotto, vedi perché vedo l'uso di questo. (La riga con una didascalia rossa, proprio sotto la riga con una didascalia gialla.) Così com'è ora, non stai davvero "modificando" il testo della nota; ti viene semplicemente chiesto di scrivere un nuovo testo, che sostituirà il testo della nota che stai (non realmente) modificando. Quindi, ho pensato che potesse essere risolto semplicemente incollando il vecchio testo in tty: se l'utente preme invio, non viene apportata alcuna modifica. (Questo programma è in Perl / MySQL, ma ho pensato che sarebbe stato più interessante chiedere una soluzione generale rispetto a "come posso farlo in Perl".)

esempio

Modifica 2:

Ecco il codice Perl, che utilizza il codice C di seguito (funziona esattamente come previsto), così come un nuovo screenshot - speriamo che questo chiarisca le cose oltre ogni dubbio :) Ancora una volta, guarda al centro dello screenshot, dove viene effettuata la modifica al testo della nota: questa volta è presente il vecchio testo, ad esempio se si desidera correggere un errore di battitura, non è necessario digitare nuovamente l'intero testo della nota.

my $edit_note_text = $edit_note_data[2];
print BOLD, 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);

better_example


L'ho fatto in Python su Stack Overflow se sei interessato. stackoverflow.com/a/29616465/117471
Bruno Bronosky

L'affermazione del problema non è chiara. Qual è il problema?

Risposte:


3

Ho appena trovato un piccolo programma C chiamato writevtche fa il trucco. Prendi qui il codice sorgente . Per farlo compilare gccbasta rimuovere prima le seguenti righe:

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

Aggiornamento . Il comando ora fa parte di console-tools , quindi disponibile in sistemi più recenti, a meno che la tua distribuzione non usi kbd invece di console-tools , nel qual caso puoi compilarlo dal sorgente (versione molto più recente, nessuna modifica necessaria).

Uso:

sudo writevt /dev/ttyN command 

Si noti che, per qualche motivo, è necessario utilizzare '\r'(o '\x0D') anziché '\n'(o '\x0A') per inviare un reso.


Questo funziona, ma c'è molto di più sbagliato di quelli inclusi. Ho dovuto abbandonare la funzione di utilizzo, fare un prognamee _, e commentare alcune chiamate di funzione inmain()
Michael Mrozek

@MichaelMrozek La _()funzione è generalmente un segno di gettext in uso. Sembra un po 'eccessivo per un pezzo di codice demo così semplice ma suppongo non faccia male.
jw013,

Il link nella risposta sopra è rotto. Ne ho trovato un altro writevt.c qui (su github.com/  grawity ) ; sembra essere essenzialmente lo stesso programma.
G-Man dice "Ripristina Monica" il

Non funziona per me - stampa solo il comando. Dending \ r o \ n stampa in modo reattivo per qualsiasi ragione; /
Antoniossss

10

Un terminale raddoppia in due modi: un dispositivo di input (come una tastiera) e un dispositivo di visualizzazione (come un monitor). Quando leggi dal terminale, ottieni ciò che viene dal dispositivo di input. Quando si scrive sul terminale, i dati vanno sul dispositivo di visualizzazione.

Non esiste un modo generale per forzare l'ingresso in un terminale. Raramente c'è bisogno di farlo. Se è necessario interagire con un programma che richiede un terminale, utilizzare un emulatore di terminale dedicato come Expect o Empty o un wrapper di terminale programmabile come Screen o Tmux . È possibile forzare l'input in una console Linux con uno ioctl . È possibile forzare l'ingresso in un emulatore di terminale X11 con strumenti come xdotool o xmacro .


Ho apportato una modifica al mio post. Dai un'occhiata e vedrai il mio pensiero.
Emanuel Berg,

@EmanuelBerg La tua modifica è difficile da capire. Stai provando a inserire a livello di codice l'input in un programma che stai utilizzando anche in modo interattivo? Se è quello che vuoi, esegui il programma screeno tmuxe usa il loro comando stuff(screen) o send-key(tmux) o la loro funzione di buffer di incolla.
Gilles 'SO- smetti di essere malvagio' il

Effettua una seconda modifica con il codice Perl incluso: l'invocazione del binario C è lì. Non lo so ... dato che era così semplice (solo una riga di codice) - è davvero meglio farlo a modo tuo (con gli strumenti screeno tmux)?
Emanuel Berg,

@EmanuelBerg Quindi sì, stai cercando screen -X stuff 'note version one'.
Gilles 'SO- smetti di essere malvagio' il

7

Almeno Linux e BSD hanno lo ioctl TIOCSTI per reinserire i caratteri nel buffer di input del terminale (fino a un limite [4096 caratteri su 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);
}

Compilalo e chiamalo come:

cmd foo bar < "$some_tty"

per respingere i personaggi su alcuni tty.

E in perl:

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

Modifica : ora mi rendo conto che è lo stesso ioctl di writeevt soluzione . Il commento e il nome del comando sono fuorvianti poiché TIOCSTI funziona per qualsiasi terminale, non solo per VT.


Dai un'occhiata alla mia seconda modifica alla domanda. Ho già compilato il codice che ho ricevuto da @htor - quello che posso vedere, funziona benissimo. Riesci a vedere qualche vantaggio usando questo codice invece? (Ma grazie per il tuo impegno in entrambi i casi.)
Emanuel Berg,

Sì. Vedi la mia modifica recente. Il punto è usare lo ioctl TIOCSTI. Il codice che ho dato fa proprio questo sul descrittore di file 0 (stdin).
Stéphane Chazelas,

3

Ho un demo più completa su StackTranslate.it .

In Python puoi fare:

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)

Ciò presuppone un "command"valore semplice ls -lae l'utilizzo del percorso tty specificato da OP.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.