Xây dựng một lệnh bằng cách đặt một chuỗi vào một tty


15

Tôi quản lý để làm điều này

echo -n " lệnh "> / dev / tty1

Các chữ cái xuất hiện và con trỏ di chuyển, nhưng chúng là "bóng ma" - nếu bạn nhấn Enter, không có gì xảy ra (chúng không ở trong stdin).

Biên tập:

Ở giữa ảnh chụp màn hình bên dưới, bạn thấy lý do tại sao tôi thấy việc sử dụng này. (Dòng có chú thích màu đỏ, ngay bên dưới dòng có chú thích màu vàng.) Như hiện tại, bạn không thực sự "chỉnh sửa" văn bản ghi chú; bạn chỉ được yêu cầu viết một văn bản mới, nó sẽ thay thế văn bản của ghi chú bạn đang (không thực sự) chỉnh sửa. Vì vậy, tôi nghĩ rằng nó có thể được khắc phục bằng cách dán văn bản cũ vào tty: nếu người dùng nhấn enter, không có sửa đổi nào được thực hiện. (Chương trình này có trong Perl / MySQL, nhưng tôi nghĩ sẽ thú vị hơn khi yêu cầu một giải pháp chung hơn là "làm thế nào để tôi làm điều này trong Perl".)

thí dụ

Chỉnh sửa 2:

Đây là mã Perl, sử dụng mã C bên dưới (hoạt động chính xác như dự định), cũng như ảnh chụp màn hình mới - hy vọng điều này sẽ làm rõ những điều không thể nghi ngờ :) Một lần nữa, hãy nhìn vào giữa ảnh chụp màn hình, nơi thực hiện chỉnh sửa đến văn bản ghi chú - lần này, văn bản cũ ở đó, ví dụ nếu bạn chỉ muốn sửa lỗi chính tả, bạn sẽ không phải gõ lại toàn bộ văn bản ghi chú.

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

tốt hơn


Tôi đã làm điều này trong Python trên Stack Overflow nếu bạn quan tâm. stackoverflow.com/a/29616465/117471
Bruno Bronosky 16/2/2017

Báo cáo vấn đề của bạn không rõ ràng. Vấn đề là gì?

Câu trả lời:


3

Tôi chỉ tìm thấy một chương trình C nhỏ gọi là writevtlừa. Lấy mã nguồn ở đây . Để làm cho nó biên dịch với gccchỉ cần loại bỏ các dòng sau:

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

Cập nhật . Lệnh hiện là một phần của công cụ bàn điều khiển , do đó có sẵn trong các hệ thống gần đây, trừ khi bản phân phối của bạn sử dụng kbd thay vì công cụ bàn điều khiển , trong trường hợp đó bạn có thể biên dịch nó từ nguồn (phiên bản mới hơn nhiều, không cần sửa đổi).

Sử dụng:

sudo writevt /dev/ttyN command 

Lưu ý rằng, vì một số lý do, bạn phải sử dụng '\r'(hoặc '\x0D') thay vì '\n'(hoặc '\x0A') để gửi trả lại.


Điều này không hoạt động, nhưng có nhiều cách sai hơn là chỉ bao gồm. Tôi đã phải mương chức năng sử dụng, làm cho một progname_, và bình luận ra một vài cuộc gọi chức năng trongmain()
Michael Mrozek

@MichaelMrozek _()Chức năng thường là dấu hiệu của gettext đang được sử dụng. Có vẻ hơi quá mức cho một đoạn mã demo đơn giản như vậy nhưng tôi cho rằng không làm tổn thương.
jw013

Các liên kết trong câu trả lời trên bị hỏng. Tôi tìm thấy một cái khác writevt.c ở đây (tại github.com/  grawity ) ; nó dường như là cùng một chương trình.
G-Man nói 'Phục hồi Monica'

Không hoạt động đối với tôi - chỉ in lệnh. Dending \ r hoặc \ n prinst rn resperctively cho bất cứ điều gì reasson; /
Antoniossss

10

Một thiết bị đầu cuối nhân đôi hai thứ: một thiết bị đầu vào (như bàn phím) và thiết bị hiển thị (như màn hình). Khi bạn đọc từ thiết bị đầu cuối, bạn sẽ nhận được những gì đến từ thiết bị đầu vào. Khi bạn ghi vào thiết bị đầu cuối, dữ liệu sẽ đi vào thiết bị hiển thị.

Không có cách nào chung để buộc đầu vào vào một thiết bị đầu cuối. Ít khi có nhu cầu làm như vậy. Nếu bạn cần tương tác với chương trình yêu cầu thiết bị đầu cuối, hãy sử dụng trình giả lập thiết bị đầu cuối chuyên dụng như Expect hoặc Empty hoặc trình bao bọc thiết bị đầu cuối có thể lập trình như Screen hoặc Tmux . Bạn có thể buộc đầu vào vào bảng điều khiển Linux bằng ioctl . Bạn có thể buộc đầu vào vào trình giả lập thiết bị đầu cuối X11 bằng các công cụ như xdotool hoặc xmacro .


Thực hiện chỉnh sửa bài viết của tôi. Có một cái nhìn và bạn sẽ thấy suy nghĩ của tôi.
Emanuel Berg

@EmanuelBerg Chỉnh sửa của bạn thật khó hiểu. Bạn đang cố gắng cung cấp đầu vào theo chương trình vào một chương trình mà bạn cũng đang sử dụng tương tác? Nếu đó là những gì bạn muốn, hãy chạy chương trình trong screenhoặc tmuxvà sử dụng lệnh stuff(màn hình) hoặc send-key(tmux) hoặc tính năng bộ đệm dán của chúng.
Gilles 'SO- ngừng trở nên xấu xa'

Thực hiện chỉnh sửa thứ hai với mã Perl được bao gồm - việc gọi nhị phân C là có. Tôi không biết ... vì nó rất đơn giản (chỉ một dòng mã) - thực sự tốt hơn để làm theo cách của bạn (với các công cụ screenhoặc tmux)?
Emanuel Berg

@EmanuelBerg Vì vậy, có, bạn đang tìm kiếm screen -X stuff 'note version one' .
Gilles 'SO- ngừng trở nên xấu xa'

7

Ít nhất Linux và BSD có TIOCSTI ioctl để đẩy các ký tự trở lại bộ đệm đầu vào đầu cuối (tối đa giới hạn [4096 ký tự trên 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);
}

Biên dịch nó và gọi nó là:

cmd foo bar < "$some_tty"

để đẩy nhân vật trở lại trên một số tty.

Và trong perl:

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

Biên tập : Tôi nhận ra bây giờ nó giống ioctl như trong giải pháp writevt . Nhận xét và tên của lệnh gây hiểu nhầm vì TIOCSTI hoạt động cho bất kỳ thiết bị đầu cuối nào, không chỉ VT.


Kiểm tra chỉnh sửa thứ hai của tôi cho câu hỏi. Tôi đã biên dịch mã tôi nhận được từ @htor - những gì tôi có thể thấy, nó hoạt động rất tốt. Bạn có thể thấy bất kỳ lợi thế bằng cách sử dụng mã này thay thế? (Nhưng cảm ơn vì nỗ lực của bạn trong cả hai trường hợp.)
Emanuel Berg

Đúng. Xem chỉnh sửa gần đây của tôi. Vấn đề là sử dụng TIOCSTI ioctl. Mã tôi đã đưa ra chỉ trên mô tả tập tin 0 (stdin).
Stéphane Chazelas

3

Tôi có bản demo hoàn chỉnh hơn trên Stack Overflow .

Trong python bạn có thể làm:

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)

Đó là giả sử một "command"giá trị đơn giản ls -lavà sử dụng đường dẫn tty được chỉ định bởi OP.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.