สร้างคำสั่งโดยใส่สตริงลงใน tty


15

ฉันจัดการเพื่อทำสิ่งนี้

echo -n " คำสั่ง "> / dev / tty1

ตัวอักษรจะปรากฏขึ้นและเคอร์เซอร์จะเคลื่อนที่ แต่มันก็เป็น "ผี" - หากคุณกดปุ่มจะEnterไม่มีอะไรเกิดขึ้น

แก้ไข:

ในกลางหน้าจอด้านล่างคุณจะเห็นว่าทำไมฉันเห็นการใช้งานนี้ (บรรทัดที่มีคำอธิบายภาพสีแดงด้านล่างบรรทัดที่มีคำอธิบายภาพสีเหลือง) เนื่องจากตอนนี้คุณไม่ได้ "แก้ไข" ข้อความบันทึกย่อจริงๆ คุณเพิ่งถูกขอให้เขียนข้อความใหม่ซึ่งจะแทนที่ข้อความของบันทึกย่อที่คุณกำลังแก้ไข (ไม่ใช่จริง ๆ ) ดังนั้นฉันคิดว่ามันสามารถแก้ไขได้โดยเพียงแค่วางข้อความเก่าลงใน tty: หากผู้ใช้กด Enter จะไม่มีการดัดแปลงใด ๆ (โปรแกรมนี้อยู่ใน 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
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 ดูเหมือนว่า overkill เล็กน้อยสำหรับรหัสตัวอย่างง่ายๆ แต่ไม่ได้ทำให้ฉันเจ็บ
jw013

การเชื่อมโยงในคำตอบข้างต้นเสีย ฉันพบอีกwritevt.c ที่นี่ (ที่ github.com/  grawity ) ; มันดูเหมือนว่าจะเป็นโปรแกรมเดียวกัน
G-Man กล่าวว่า 'Reinstate Monica'

ใช้งานไม่ได้สำหรับฉัน - พิมพ์เฉพาะคำสั่ง Dending \ r หรือ \ n prinst rn resperctively สำหรับ reasson อะไรก็ตาม /
Antoniossss

10

เทอร์มินัลเพิ่มเป็นสองสิ่ง: อุปกรณ์อินพุต (เช่นแป้นพิมพ์) และอุปกรณ์แสดงผล (เช่นจอภาพ) เมื่อคุณอ่านจากเทอร์มินัลคุณจะได้สิ่งที่มาจากอุปกรณ์อินพุต เมื่อคุณเขียนลงในเทอร์มินัลข้อมูลจะไปยังอุปกรณ์แสดงผล

ไม่มีวิธีทั่วไปในการบังคับให้อินพุตเข้าสู่เทอร์มินัล ไม่จำเป็นต้องทำเช่นนั้น หากคุณจำเป็นต้องโต้ตอบกับโปรแกรมที่ต้องใช้ขั้วให้ใช้เฉพาะจำลอง terminal เช่นคาดหวังหรือลบหรือขั้วตั้งโปรแกรมกระดาษห่อเช่นหน้าจอหรือTmux คุณสามารถบังคับให้ใส่ลงในคอนโซลลินุกซ์กับ IOCTL คุณสามารถบังคับให้ใส่ลงในสถานีจำลอง X11 ด้วยเครื่องมือเช่นxdotoolหรือxmacro


แก้ไขโพสต์ของฉัน ลองดูแล้วคุณจะเห็นความคิดของฉัน
Emanuel Berg

@EmanuelBerg การแก้ไขของคุณยากที่จะเข้าใจ คุณพยายามป้อนข้อมูลเข้าสู่โปรแกรมโดยใช้โปรแกรมแบบโต้ตอบหรือไม่? หากนั่นคือสิ่งที่คุณต้องการให้เรียกใช้โปรแกรมในscreenหรือtmuxใช้คำสั่งstuff(หน้าจอ) หรือsend-key(tmux) หรือคุณสมบัติการวางบัฟเฟอร์
Gilles 'หยุดความชั่วร้าย'

ทำการแก้ไขครั้งที่สองโดยมีรหัส Perl รวมอยู่ด้วยการร้องขอของไบนารี C จะมี ฉันไม่รู้ ... เพราะมันง่ายมาก (แค่หนึ่งบรรทัดของโค้ด) - มันดีกว่าที่จะทำในแบบของคุณ (ด้วยscreenหรือtmuxเครื่องมือ)?
Emanuel Berg

@EmanuelBerg screen -X stuff 'note version one'ดังนั้นใช่คุณกำลังมองหา
Gilles 'หยุดความชั่วร้าย'

7

อย่างน้อย Linux และ BSDs มี 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

และใน perl:

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

แก้ไข : ฉันรู้ว่าตอนนี้มันเป็น ioctl เช่นเดียวกับในโซลูชั่นwritevt ความคิดเห็นและชื่อของคำสั่งทำให้เข้าใจผิดเนื่องจาก TIOCSTI ใช้งานได้กับเทอร์มินัลใด ๆ ไม่ใช่แค่ VTs


ลองดูการแก้ไขคำถามที่สองของฉัน ฉันรวบรวมรหัสที่ฉันได้รับจาก @htor แล้ว - สิ่งที่ฉันเห็นมันใช้งานได้ดี คุณเห็นข้อดีของการใช้รหัสนี้แทนไหม (แต่ขอบคุณสำหรับความพยายามของคุณในทั้งสองกรณี)
Emanuel Berg

ใช่. ดูการแก้ไขล่าสุดของฉัน ประเด็นคือการใช้ TIOCSTI ioctl รหัสที่ฉันให้ทำแค่นั้นกับ file descriptor 0 (stdin)
Stéphane Chazelas

ไม่ใช่ทุกคนที่มี TIOCSTI อีกต่อไป ห้าปีหลังจากคำตอบนี้ถูกเขียนผู้คนเริ่มปล่อยมันออกมาจากเมล็ด unix.stackexchange.com/q/406690/5132
JdeBP

3

ฉันมีการสาธิตที่สมบูรณ์มากขึ้นไปบนกองมากเกิน

ในงูหลามคุณสามารถทำได้:

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)

นั่นคือสมมติว่ามี"command"ค่าอย่างง่ายls -laและใช้เส้นทาง tty ที่ระบุโดย OP

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.