Bangun sebuah perintah dengan memasukkan string ke dalam tty

15

Saya berhasil melakukan ini

echo -n " command "> / dev / tty1

Huruf-huruf muncul, dan kursor bergerak, tetapi mereka adalah "hantu" - jika Anda menekan Enter, tidak ada yang terjadi (mereka tidak ada di stdin).

Edit:

Di tengah tangkapan layar di bawah, Anda tahu mengapa saya melihat penggunaan ini. (Garis dengan teks merah, tepat di bawah garis dengan teks kuning.) Seperti sekarang, Anda tidak benar-benar "mengedit" teks catatan; Anda hanya diminta untuk menulis teks baru, yang akan menggantikan teks dari catatan yang sedang Anda edit. Jadi, saya pikir itu bisa diatasi dengan hanya menempelkan teks lama ke tty: jika pengguna mengklik masuk, tidak ada modifikasi yang dilakukan. (Program ini di Perl / MySQL, tapi saya pikir akan lebih menarik untuk meminta solusi umum daripada "bagaimana saya melakukan ini di Perl".)

contoh

Edit 2:

Berikut adalah kode Perl, yang menggunakan kode C di bawah ini (berfungsi persis seperti yang dimaksudkan), serta tangkapan layar baru - mudah-mudahan ini akan memperjelas hal-hal tanpa keraguan :) Sekali lagi, lihat di tengah tangkapan layar, tempat pengeditan dibuat ke teks catatan - kali ini, teks lama ada di sana, misalnya jika Anda hanya ingin memperbaiki kesalahan ketik, Anda tidak perlu mengetik ulang seluruh teks catatan.

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

lebih baik_contoh

Emanuel Berg
sumber
Saya melakukan ini dengan Python di Stack Overflow jika Anda tertarik. stackoverflow.com/a/29616465/117471
Bruno Bronosky
Pernyataan masalah Anda tidak jelas. Apa masalahnya?

Jawaban:

3

Saya baru saja menemukan program C kecil yang disebut writevtyang melakukan trik. Ambil kode sumber di sini . Untuk membuatnya dikompilasi dengan gcchanya menghapus baris berikut terlebih dahulu:

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

Perbarui . Perintah sekarang menjadi bagian dari konsol-alat , sehingga tersedia dalam sistem yang lebih baru, kecuali distribusi Anda menggunakan kbd bukan konsol-alat , dalam hal ini Anda dapat mengkompilasinya dari sumber (versi yang jauh lebih baru, tidak ada modifikasi yang diperlukan).

Pemakaian:

sudo writevt /dev/ttyN command 

Perhatikan bahwa, karena alasan tertentu, Anda harus menggunakan '\r'(atau '\x0D') alih-alih '\n'(atau '\x0A') untuk mengirim pengembalian.

Teluk Persia
sumber
Ini memang berhasil, tetapi ada yang jauh lebih salah daripada hanya yang termasuk. Saya harus membuang fungsi penggunaan, membuat prognamedan _, dan mengomentari beberapa fungsi panggilanmain()
Michael Mrozek
@MichaelMrozek _()Fungsi ini biasanya merupakan tanda gettext yang digunakan. Tampaknya sedikit berlebihan untuk sepotong kode demo yang sederhana tetapi saya kira tidak ada salahnya.
jw013
The Link di jawaban di atas rusak. Saya menemukan yang lain di writevt.c sini (di github.com/  grawity ) ; tampaknya pada dasarnya program yang sama.
G-Man Mengatakan 'Reinstate Monica'
Tidak bekerja untuk saya - hanya mencetak perintah. Terus-menerus atau terus-menerus untuk alasan apa pun; /
Antoniossss
10

Terminal berfungsi ganda sebagai dua hal: perangkat input (seperti keyboard) dan perangkat layar (seperti monitor). Ketika Anda membaca dari terminal, Anda mendapatkan apa yang berasal dari perangkat input. Saat Anda menulis ke terminal, data masuk ke perangkat layar.

Tidak ada cara umum untuk memaksa input ke terminal. Jarang ada kebutuhan untuk melakukannya. Jika Anda perlu berinteraksi dengan program yang membutuhkan terminal, gunakan emulator terminal khusus seperti Expect or Empty , atau pembungkus terminal yang dapat diprogram seperti Screen atau Tmux . Anda dapat memaksa input ke konsol Linux dengan ioctl . Anda dapat memaksa input ke emulator terminal X11 dengan alat-alat seperti xdotool atau xmacro .

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Edit posting saya. Lihatlah dan Anda akan melihat pemikiran saya.
Emanuel Berg
@EmanuelBerg Hasil edit Anda sulit dimengerti. Apakah Anda mencoba memasukkan input secara terprogram ke dalam program yang juga Anda gunakan secara interaktif? Jika itu yang Anda inginkan, jalankan program di screendan tmuxdan gunakan perintah stuff(layar) atau send-key(tmux) atau fitur buffer paste.
Gilles 'SO- stop being evil'
Membuat edit kedua dengan kode Perl disertakan - doa dari biner C ada di sana. Saya tidak tahu ... karena sangat sederhana (hanya satu baris kode) - apakah benar-benar lebih baik melakukannya dengan cara Anda (dengan alat screenatau tmux)?
Emanuel Berg
@ EmanuelBerg Jadi ya, Anda sedang mencari screen -X stuff 'note version one'.
Gilles 'SO- stop being evil'
7

Setidaknya Linux dan BSD memiliki TIOCSTI ioctl untuk mendorong karakter kembali ke buffer input terminal (hingga batas [4096 karakter di 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);
}

Kompilasi, dan sebut sebagai:

cmd foo bar < "$some_tty"

untuk mendorong karakter kembali pada tty tertentu.

Dan dalam perl:

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

Sunting : Saya menyadari sekarang ini adalah ioctl yang sama seperti pada solusi writevt . Komentar dan nama perintah itu menyesatkan karena TIOCSTI bekerja untuk terminal apa pun, bukan hanya VT.

Stéphane Chazelas
sumber
Lihatlah hasil edit saya yang kedua untuk pertanyaan itu. Saya sudah mengkompilasi kode yang saya dapatkan dari @htor - apa yang bisa saya lihat, ini berfungsi dengan baik. Bisakah Anda melihat keuntungan menggunakan kode ini? (Tapi terima kasih atas upaya Anda dalam kedua kasus ini.)
Emanuel Berg
Iya. Lihat hasil edit terbaru saya. Intinya adalah menggunakan TIOCSTI ioctl. Kode yang saya berikan tidak hanya itu pada file descriptor 0 (stdin).
Stéphane Chazelas
3

Saya memiliki demo yang lebih lengkap tentang Stack Overflow .

Dengan python Anda dapat melakukan:

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)

Itu dengan asumsi "command"nilai sederhana ls -ladan menggunakan jalur tty yang ditentukan oleh OP.

Bruno Bronosky
sumber