Создайте команду, поместив строку в 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);

better_example

Эмануэль Берг
источник
Я сделал это в Python поверх Stack Overflow, если вам интересно. stackoverflow.com/a/29616465/117471
Бруно Броноски
Ваша проблема не ясна. В чем проблема?

Ответы:

3

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

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

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

Использование:

sudo writevt /dev/ttyN command 

Обратите внимание, что по какой-то причине вы должны использовать '\r'(или '\x0D') вместо '\n'(или '\x0A') для отправки возврата.

Персидский залив
источник
Это работает, но есть гораздо больше ошибок, чем просто включает. Мне пришлось отказаться от использования функции, сделать prognameи _и закомментировать несколько вызовов функцийmain()
Майкл Мрозек
@MichaelMrozek _()Функция обычно является признаком использования gettext . Кажется, немного излишним для такого простого фрагмента демонстрационного кода, но я полагаю, это не повредит.
jw013
Ссылка в ответе выше сломана. Я нашел другой writevt.c здесь (на github.com/  grawity ) ; Похоже, это по сути та же самая программа.
G-Man говорит: «Восстановите Монику»
У меня не работает - только печатает команду. Отвечать на вопрос по любой причине; /
Антониосс
10

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

Не существует общего способа принудительного ввода данных в терминал. В этом нет необходимости. Если вам нужно взаимодействовать с программой, для которой требуется терминал, используйте специальный эмулятор терминала, такой как Expect или Empty , или программируемую оболочку терминала, такую ​​как Screen или Tmux . Вы можете принудительно ввести ввод в консоль Linux с помощью ioctl . Вы можете принудительно ввести ввод в эмулятор терминала X11 с помощью таких инструментов, как xdotool или xmacro .

Жиль "ТАК - прекрати быть злым"
источник
Внес изменения в мой пост. Посмотрите, и вы увидите мое мышление.
Эмануэль Берг
@EmanuelBerg Ваше редактирование трудно понять. Вы пытаетесь программно вводить ввод в программу, которую вы также используете в интерактивном режиме? Если это то, что вы хотите, запустите программу в screenили tmuxи используйте их stuff(screen) или send-key(tmux) команду или их функцию вставки буфера.
Жиль "ТАК - перестать быть злым"
Произведено второе редактирование с включенным кодом Perl - здесь есть вызов двоичного кода C. Я не знаю ... как это было так просто (всего одна строка кода) - действительно ли лучше сделать это по-своему (с помощью инструментов screenили tmux)?
Эмануэль Берг
@EmanuelBerg Так что да, вы ищете screen -X stuff 'note version one'.
Жиль "ТАК - перестать быть злым"
7

По крайней мере, Linux и BSD имеют ioctl TIOCSTI для отправки символов обратно в буфер ввода терминала (до ограничения [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.

И в Perl:

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

Изменить : теперь я понимаю, что это тот же ioctl, что и в решении writevt . Комментарий и название команды вводят в заблуждение, поскольку TIOCSTI работает для любого терминала, а не только для VT.

Стефан Шазелас
источник
Проверьте мое второе редактирование на вопрос. Я уже скомпилировал код, полученный от @htor - что я вижу, он прекрасно работает. Можете ли вы увидеть какие-либо преимущества использования этого кода вместо этого? (Но спасибо за ваши усилия в любом случае.)
Эмануэль Берг
Да. Смотрите мое недавнее редактирование. Дело в том, чтобы использовать TIOCSTI ioctl. Код, который я дал, делает это в файловом дескрипторе 0 (stdin).
Стефан Шазелас