Skonstruuj polecenie, wstawiając ciąg do tty


15

Udało mi się to zrobić

echo -n " polecenie "> / dev / tty1

Pojawiają się litery i kursor się porusza, ale są one „duchami” - jeśli trafisz Enter, nic się nie wydarzy (nie są ustawione na standardowe).

Edytować:

Pośrodku poniższego zrzutu ekranu widać, dlaczego widzę zastosowanie tego. (Linia z czerwonym podpisem, tuż pod linią z żółtym podpisem.) W tej chwili tak naprawdę nie „edytujesz” tekstu notatki; zostałeś poproszony o napisanie nowego tekstu, który zastąpi tekst notatki, którą (tak naprawdę) nie edytujesz. Pomyślałem więc, że można temu zaradzić, po prostu wklejając stary tekst do tty: jeśli użytkownik naciśnie klawisz Enter, nie zostaną wprowadzone żadne zmiany. (Ten program jest w Perlu / MySQL, ale pomyślałem, że bardziej interesujące byłoby poprosić o ogólne rozwiązanie niż „jak to zrobić w Perlu”).

przykład

Edycja 2:

Oto kod Perla, który używa poniższego kodu C (działa dokładnie zgodnie z przeznaczeniem), a także nowy zrzut ekranu - mam nadzieję, że wyjaśni to ponad wszelką wątpliwość :) Ponownie spójrz na środek zrzutu ekranu, w którym dokonano edycji do tekstu notatki - tym razem znajduje się stary tekst, na przykład jeśli chcesz tylko poprawić literówkę, nie będziesz musiał ponownie wpisywać całego tekstu notatki.

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);

lepszy_przykład


Zrobiłem to w Pythonie na Stack Overflow, jeśli jesteś zainteresowany. stackoverflow.com/a/29616465/117471
Bruno Bronosky

Twoje zgłoszenie problemu nie jest jasne. Jaki jest problem?

Odpowiedzi:


3

Właśnie znalazłem mały program o nazwie C, writevtktóry działa. Pobierz kod źródłowy tutaj . Aby go skompilować, gccnajpierw usuń następujące linie:

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

Aktualizacja . Polecenie jest teraz częścią narzędzi konsolowych , a zatem dostępnych w nowszych systemach, chyba że twoja dystrybucja używa kbd zamiast narzędzi konsolowych , w którym to przypadku możesz skompilować go ze źródła (znacznie nowsza wersja, nie jest wymagana modyfikacja).

Stosowanie:

sudo writevt /dev/ttyN command 

Pamiętaj, że z jakiegoś powodu musisz użyć '\r'(lub '\x0D') zamiast '\n'(lub '\x0A'), aby wysłać zwrot.


To działa, ale jest znacznie więcej błędów niż tylko te. Musiałem porzucić funkcję użytkowania, zrobić prognamea _i skomentować kilka wywołań funkcjimain()
Michael Mrozek

@MichaelMrozek _()Funkcja jest zwykle oznaką użycia gettext . Wydaje się to trochę przesadne jak na tak prosty fragment kodu demonstracyjnego, ale chyba nie zaszkodzi.
jw013,

Ogniwo w powyższym odpowiedź jest uszkodzony. Znalazłem inny writevt.c tutaj (na github.com/  grawity ) ; wydaje się, że jest to zasadniczo ten sam program.
G-Man mówi „Przywróć Monikę”

Nie działa dla mnie - drukuje tylko polecenie. W oczekiwaniu na odpowiedź lub niezależnie od przyczyny; /
Antoniossss

10

Terminal podwaja się jako dwie rzeczy: urządzenie wejściowe (takie jak klawiatura) i urządzenie wyświetlające (takie jak monitor). Kiedy czytasz z terminala, dostajesz to, co pochodzi z urządzenia wejściowego. Gdy piszesz do terminala, dane trafiają na urządzenie wyświetlające.

Nie ma ogólnego sposobu na zmuszanie wejścia do terminala. Rzadko jest taka potrzeba. Jeśli potrzebujesz wejść w interakcję z programem, który wymaga terminala, użyj dedykowanego emulatora terminala, takiego jak Expect lub Empty , lub programowalnego otoki terminala, takiego jak Screen lub Tmux . Możesz wymusić wejście do konsoli Linux za pomocą ioctl . Możesz wymusić wejście do emulatora terminala X11 za pomocą narzędzi takich jak xdotool lub xmacro .


Dokonałem edycji mojego postu. Spójrz, a zobaczysz moje myślenie.
Emanuel Berg,

@EmanuelBerg Twoja zmiana jest trudna do zrozumienia. Czy próbujesz programowo wprowadzić dane wejściowe do programu, którego używasz również interaktywnie? Jeśli tego chcesz, uruchom program w screenlub tmuxi użyj ich polecenia stuff(screen) lub send-key(tmux) lub funkcji bufora wklejania.
Gilles „SO- przestań być zły”

Wykonałem drugą edycję z dołączonym kodem Perla - jest tam wywołanie pliku binarnego C. Nie wiem ... bo to było takie proste (tylko jedna linia kodu) - czy naprawdę lepiej jest robić to po swojemu (za pomocą narzędzi screenlub tmux)?
Emanuel Berg

@EmanuelBerg Więc tak, szukasz screen -X stuff 'note version one'.
Gilles „SO- przestań być zły”

7

Przynajmniej Linux i BSD mają ioctl TIOCSTI do wypychania znaków z powrotem do bufora wejściowego terminala (do limitu [4096 znaków w Linuksie]):

#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);
}

Skompiluj go i wywołaj jako:

cmd foo bar < "$some_tty"

aby zepchnąć postacie z powrotem na jakiś tty.

I w perlu:

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

Edycja : Zdaję sobie sprawę, że teraz jest to ten sam ioctl, co w rozwiązaniu zapisu . Komentarz i nazwa polecenia są mylące, ponieważ TIOCSTI działa na dowolnym terminalu, nie tylko VT.


Sprawdź moją drugą edycję pytania. Skompilowałem już kod, który otrzymałem od @htor - co widzę, działa świetnie. Czy widzisz jakieś zalety korzystania z tego kodu? (Ale dziękuję za twój wysiłek w obu przypadkach.)
Emanuel Berg

Tak. Zobacz moją ostatnią edycję. Chodzi o to, aby użyć ioctl TIOCSTI. Kod, który podałem, robi to tylko na deskryptorze pliku 0 (stdin).
Stéphane Chazelas

Nie każdy ma już TIOCSTI. Pięć lat po napisaniu tej odpowiedzi ludzie zaczęli upuszczać ją z jądra. unix.stackexchange.com/q/406690/5132
JdeBP

3

Mam pełniejsze demo na Stack Overflow .

W pythonie możesz wykonać:

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)

To zakłada prostą "command"wartość ls -lai użycie ścieżki tty określonej przez OP.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.