Побудуйте команду, додавши рядок у tty


15

Мені вдалося це зробити

echo -n " команда "> / dev / tty1

Букви з’являються, і курсор рухається, але вони є «привидами» - якщо ти вдариш Enter, нічого не станеться (вони не в stdin).

Редагувати:

У середині скріншоту нижче ви бачите, чому я бачу використання цього. (Рядок із червоним заголовком, прямо під рядком із жовтим заголовком.) Як і зараз, ви насправді не «редагуєте» текст примітки; вас просто попросять написати новий текст, який замінить текст замітки, яку ви (не дуже) редагуєте. Таким чином, я подумав, що це можна виправити, просто вставивши старий текст у tty: якщо користувач звернеться, внесення змін не буде здійснено. (Ця програма знаходиться в Perl / MySQL, але я подумав, що було б цікавіше попросити загальне рішення, ніж "як це зробити в Perl".)

приклад

Редагувати 2:

Ось код Perl, який використовує код C нижче (працює точно так, як було призначено), а також новий скріншот - сподіваємось, це з’ясує речі без сумніву :) Знову подивіться на середину екрана, де зроблено редагування до тексту ноти - цього разу старий текст є, наприклад, якщо ви просто хотіли зафіксувати помилку друку, вам не доведеться повторно вводити весь текст ноти.

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

краще_приклад


Я зробив це в Python over на Stack Overflow, якщо вас цікавить. stackoverflow.com/a/29616465/117471
Bruno Bronosky

Твоя проблема проблеми не зрозуміла. В чому проблема?

Відповіді:


3

Я щойно знайшов невелику програму на C, яка називається writevtтрюком. Візьміть вихідний код тут . Щоб зробити компіляцію, gccпросто спочатку видаліть наступні рядки:

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

Оновлення . Команда тепер є частиною консольних інструментів , тому доступна в більш сучасних системах, якщо ваш дистрибутив не використовує kbd замість консольних інструментів , і в цьому випадку ви можете їх скласти з джерела (набагато новіша версія, ніяких модифікацій не потрібно).

Використання:

sudo writevt /dev/ttyN command 

Зауважте, що вам потрібно з якоїсь причини використовувати '\r'(або '\x0D') замість '\n'(або '\x0A'), щоб надіслати повернення.


Це справді працює, але є спосіб, більш неправильний, ніж лише те, що включає. Мені довелося скинути функцію використання, зробити prognameі _та прокоментувати кілька функцій дзвінкаmain()
Michael Mrozek

@MichaelMrozek _()Функція, як правило, є ознакою використовуваного gettext . Здається, трохи надмірного рівня для такого простого демо-версії, але, мабуть, це не зашкодить.
jw013

Посилання у відповіді вище зламана. Я знайшов іншого writevt.c тут (на github.com/  grawity ) ; виявляється, що це по суті та сама програма.
G-Man каже: "Відновіть Моніку"

Не працює для мене - тільки друкує команду. Позбувшись \ r або \ n prinst rn з упевненістю на будь-яку причину; /
Antoniossss

10

Термінал складається з двох елементів: пристрою введення (наприклад, клавіатури) і пристрою відображення (наприклад, монітора). Коли ви читаєте з терміналу, ви отримуєте те, що надходить від пристрою введення. Коли ви пишете в термінал, дані надходять на пристрій відображення.

Не існує загального способу примусового введення в термінал. Рідко виникає потреба в цьому. Якщо вам потрібно взаємодіяти з програмою, якій потрібен термінал, використовуйте спеціальний емулятор терміналу, такий як Expect або Empty , або програмовану термінальну обгортку, наприклад, Screen або Tmux . Ви можете примусити ввести в консоль Linux за допомогою ioctl . Ви можете примусити ввести в емулятор терміналу X11 такі інструменти, як xdotool або xmacro .


Внесли зміни в свою публікацію. Поглянь, і ти побачиш моє мислення.
Емануель Берг

@EmanuelBerg Вашу редакцію важко зрозуміти. Чи намагаєтесь ви програмно подавати введення в програму, яку ви також використовуєте інтерактивно? Якщо ви цього хочете, запустіть програму в screenабо tmuxвикористовуйте команду stuff(екран) або send-key(tmux) або функцію їх буфера.
Жил "ТАК - перестань бути злим"

Зробив друге редагування з включеним кодом Perl - виклик бінарного C є. Я не знаю ... як це було так просто (лише один рядок коду) - чи справді краще зробити це по-своєму (за допомогою screenабо tmuxінструментів)?
Емануель Берг

@EmanuelBerg Так що так, ви шукаєте screen -X stuff 'note version one'.
Жил "ТАК - перестань бути злим"

7

Принаймні Linux та BSD мають TIOCSTI ioctl для відштовхування символів до термінального вхідного буфера (до обмеження [4096 символів в 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);
}

Складіть його і назвіть так:

cmd foo bar < "$some_tty"

щоб підштовхнути символів назад на якусь tty.

І в перл:

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

Редагувати : Я зараз розумію, що це той самий йоктл, що і в розчині writevt . Коментар та назва команди вводять в оману, оскільки TIOCSTI працює для будь-якого терміналу, а не лише VT.


Перегляньте мою другу редакцію питання. Я вже склав код, який я отримав від @htor - те, що я бачу, він чудово працює. Чи можете ви бачити якісь переваги, використовуючи цей код замість цього? (Але дякую за ваші зусилля в будь-якому випадку.)
Емануель Берг

Так. Дивіться мою останню редакцію. Сенс у тому, щоб використовувати йоктл TIOCSTI. Код, який я дав, робить саме це у дескрипторі файлів 0 (stdin).
Стефан Шазелас

Не всі вже мають TIOCSTI. Через п'ять років після написання цієї відповіді люди почали скидати її з ядер. unix.stackexchange.com/q/406690/5132
JdeBP

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.