বাশ তার নিজস্ব ইনপুট প্রবাহে লিখতে পারে?


39

ইন্টারেক্টিভ বাশ শেলের মধ্যে এমন কোনও কমান্ড প্রবেশ করা সম্ভব হবে যা কিছু পাঠ্যকে আউটপুট দেয় যাতে এটি পরবর্তী কমান্ড প্রম্পটে উপস্থিত হয়, যেমন ব্যবহারকারী সেই প্রম্পটে সেই পাঠ্যটি টাইপ করেছেন?

আমি এমন sourceএকটি স্ক্রিপ্টে সক্ষম হতে চাই যা একটি কমান্ড-লাইন তৈরি করবে এবং এটিকে আউটপুট দেয় যাতে স্ক্রিপ্ট শেষ হওয়ার পরে প্রম্পটটি ফিরে আসে যাতে এটি enterকার্যকর করার জন্য চাপ দেওয়ার আগে ব্যবহারকারী optionচ্ছিকভাবে এটি সম্পাদনা করতে পারে।

এটি দিয়ে অর্জন করা যেতে পারে xdotoolতবে এটি কেবল তখনই কাজ করে যখন টার্মিনালটি একটি এক্স উইন্ডোতে থাকে এবং কেবল এটি ইনস্টল করা হলে।

[me@mybox] 100 $ xdotool type "ls -l"
[me@mybox] 101 $ ls -l  <--- cursor appears here!

এটি কি কেবল ব্যাশ ব্যবহার করে করা যায়?


আমি ভাবছি এটি প্রত্যাশার সাথে কঠিন হওয়া উচিত নয়, যদি আপনি তা সহ্য করতে পারেন, এবং এটি একটি সাবশেল চালনা করতে পারেন; তবে আমি সত্যিকারের উত্তর পোস্ট করার জন্য এটি যথেষ্ট মনে করি না।
ট্রিপলি

উত্তর:


40

এর সাহায্যে zshআপনি print -zপরবর্তী প্রম্পটের জন্য কিছু পাঠ্য লাইন সম্পাদক বাফারে রাখতে পারেন:

print -z echo test

echo testআপনি পরবর্তী প্রম্পটে সম্পাদনা করতে পারেন এমন লাইন সম্পাদকটিকে প্রাইম করবে ।

আমি মনে করি না এর bashএকই বৈশিষ্ট্য রয়েছে তবে অনেকগুলি সিস্টেমে আপনি টার্মিনাল ডিভাইস ইনপুট বাফারটি প্রাইম করে নিতে পারেন TIOCSTI ioctl():

perl -e 'require "sys/ioctl.ph"; ioctl(STDIN, &TIOCSTI, $_)
  for split "", join " ", @ARGV' echo test

echo testটার্মিনাল ডিভাইস ইনপুট বাফারে প্রবেশ করানো হবে, যেমন টার্মিনাল থেকে প্রাপ্ত।

@ মাইকের Terminologyপদ্ধতির উপর আরও পোর্টেবল প্রকরণ এবং এটি যে নিরাপত্তা ত্যাগ করে না তা হ'ল টার্মিনাল এমুলেটরটিকে মোটামুটি মানক query status reportপালানোর ক্রম প্রেরণ করা : <ESC>[5nযা টার্মিনালগুলি অবিস্মরণীয়ভাবে উত্তর দেয় (তাই ইনপুট হিসাবে) <ESC>[0nএবং আপনি যে স্ট্রিংটি সন্নিবেশ করতে চান তার সাথে বাঁধেন:

bind '"\e[0n": "echo test"'; printf '\e[5n'

জিএনইউর মধ্যে থাকলে আপনিও এটি screenকরতে পারেন:

screen -X stuff 'echo test'

এখন, TIOCSTI ioctl পদ্ধতির ব্যতীত, আমরা টার্মিনাল এমুলেটরটিকে কিছু স্ট্রিং পাঠানোর জন্য বলছি যেন টাইপ করা হয় ed যদি সেই স্ট্রিংটি আগে আসে readline( bashএর লাইন সম্পাদক) টার্মিনাল স্থানীয় প্রতিধ্বনিকে অক্ষম করেছে, তবে সেই স্ট্রিংটি শেল প্রম্পটে প্রদর্শিত হবে না , ডিসপ্লেটি কিছুটা বিশৃঙ্খলা করিয়ে দেবে।

এর আশেপাশে কাজ করতে, আপনি হয় টার্মিনালে অনুরোধটি প্রেরণে কিছুটা বিলম্ব করতে পারেন তা নিশ্চিত করার জন্য যে পাঠ্যলাইন দ্বারা প্রতিধ্বনি অক্ষম করা হয়েছে তখন প্রতিক্রিয়া এসেছে।

bind '"\e[0n": "echo test"'; ((sleep 0.05;  printf '\e[5n') &)

(এখানে আপনার sleepসমর্থন সাব-দ্বিতীয় রেজোলিউশন ধরে নিচ্ছেন )।

আদর্শভাবে আপনি যেমন কিছু করতে চান:

bind '"\e[0n": "echo test"'
stty -echo
printf '\e[5n'
wait-until-the-response-arrives
stty echo

তবে bash(বিপরীতে zsh) এর মতো কোনও সমর্থন wait-until-the-response-arrivesনেই যা প্রতিক্রিয়াটি পড়ে না।

তবে এর has-the-response-arrived-yetসাথে এর বৈশিষ্ট্য রয়েছে read -t0:

bind '"\e[0n": "echo test"'
saved_settings=$(stty -g)
stty -echo -icanon min 1 time 0
printf '\e[5n'
until read -t0; do
  sleep 0.02
done
stty "$saved_settings"

আরও পড়া

@ স্টারফ্রাইয়ের উত্তরটি দেখুন যা @ মাইক্রোজার এবং আমার নিজের দ্বারা আরও কয়েকটি বিশদ তথ্য দিয়ে দেওয়া দুটি সমাধানের প্রসারিত হয়।


আমি bind '"\e[0n": "echo test"'; printf '\e[5n'সম্ভবত বশ-কেবল উত্তরটি খুঁজছি বলে আমি মনে করি । এটা আমার জন্য কাজ করে. তবে আমি ^[[0nআমার প্রম্পটের আগেও মুদ্রিত হয়ে যাচ্ছি। আমি আবিষ্কার করেছি এটি যখন $PS1একটি সাবশেল থাকে তখন ঘটে । PS1='$(:)'বাইন্ড কমান্ডের আগে আপনি এটি পুনরুত্পাদন করতে পারেন । কেন এটি ঘটবে এবং এ সম্পর্কে কিছু করা যেতে পারে?
স্টারফাই

যদিও এই উত্তরের সমস্ত কিছু সঠিক, প্রশ্নটি বাশের জন্য ছিল, zsh নয়। কখনও কখনও কোন শেলটি ব্যবহার করা যায় তা আমাদের পছন্দ করে না।
ফ্যালসনামস

@ ফালসনেমস কেবল প্রথম অনুচ্ছেদটি zsh এর জন্য। বাকীটি হয় শেল অগনস্টিক বা বাশ নির্দিষ্ট। প্রশ্নোত্তর কেবলমাত্র ব্যাশ ব্যবহারকারীদের জন্য কার্যকর হতে হবে না।
স্টাফেন চেজেলাস

1
@ স্টারফ্রি মনে হচ্ছে আপনি কি কেবল \rমাথার উপর ইটুর লাগাতে পারতেন $PS1? এটি $PS1যথেষ্ট দীর্ঘ হলে কাজ করা উচিত । যদি না হয় তবে ^[[Mসেখানে রাখুন।
মাইকসার্ভ

@ মিমকিজার - rকৌশলটি করে। এটি অবশ্যই আউটপুটটিকে আটকাতে পারে না, চোখটি দেখার আগে এটি কেবল ওভাররাইট করা। আমি অনুমান করি ^[[Mযে প্রম্পটের চেয়ে লম্বা হলে ইনজেকশনযুক্ত পাঠ্য সাফ করার জন্য লাইনটি মুছে ফেলবে। এটা কি ঠিক (আমার কাছে থাকা এএনএসআই পলায়নের তালিকায় এটি খুঁজে পাইনি)?
স্টারফাই

24

এই উত্তরটি আমার নিজের বোঝার স্পষ্টতা হিসাবে সরবরাহ করা হয়েছে এবং আমার আগে @ স্টাফেনচাজেলাস এবং @ মাইক্রোজার দ্বারা অনুপ্রাণিত হয়েছেন।

টি এল; ডিআর

  • bashবাহ্যিক সাহায্য ব্যতীত এটি করা সম্ভব নয় ;
  • এটি করার সঠিক উপায় সাথে আছেন পাঠান টার্মিনাল ইনপুট ioctl কিন্তু
  • সবচেয়ে সহজ কার্যক্ষম bashসমাধান ব্যবহার করে bind

সহজ সমাধান

bind '"\e[0n": "ls -l"'; printf '\e[5n'

বাশের একটি শেল বিল্টিন রয়েছে যা bindএকটি শেল কমান্ড কার্যকর করার জন্য একটি কী সিকোয়েন্স প্রাপ্ত হলে অনুমতি দেয়। সংক্ষেপে, শেল কমান্ডের আউটপুট শেলের ইনপুট বাফারে লেখা হয়।

$ bind '"\e[0n": "ls -l"'

মূল সিকোয়েন্স \e[0n( <ESC>[0n) হ'ল একটি এএনএসআই টার্মিনাল এস্কেপ কোড যা কোনও টার্মিনাল প্রেরণ করে যে এটি স্বাভাবিকভাবে কাজ করছে indicate এটি কোনও ডিভাইস স্থিতি প্রতিবেদনের অনুরোধ হিসাবে এটি প্রেরণ করে যা প্রেরণ করা হয় <ESC>[5n

echoপাঠ্যটিকে ইনজেক্ট করতে দেয় এমন কোনও প্রতিক্রিয়াকে আবদ্ধ করে আমরা যখনই ডিভাইসের স্থিতির অনুরোধ করে এটি পাঠাতে পারি এবং এটি একটি <ESC>[5nপালানোর ক্রম পাঠিয়ে সম্পন্ন করে ।

printf '\e[5n'

এটি কাজ করে এবং সম্ভবত মূল প্রশ্নের উত্তর দেওয়ার পক্ষে যথেষ্ট কারণ অন্য কোনও সরঞ্জাম জড়িত নেই। এটি খাঁটি bashতবে একটি ভাল আচরণের টার্মিনালের উপর নির্ভর করে (কার্যত সবগুলিই রয়েছে)।

এটি কমান্ড লাইনে প্রতিধ্বনিত পাঠ্যটি ব্যবহার করতে প্রস্তুত যেমন এটি টাইপ করা হয়েছে been এটি সংযোজন, সম্পাদনা করা এবং টিপে ENTERএটি কার্যকর করা যায়।

যোগ \nআবদ্ধ কমান্ড এটি স্বয়ংক্রিয়ভাবে মৃত্যুদন্ড কার্যকর আছে।

তবে এই সমাধানটি কেবলমাত্র বর্তমান টার্মিনালে (যা মূল প্রশ্নের ক্ষেত্রের মধ্যে রয়েছে) কাজ করে। এটি একটি ইন্টারেক্টিভ প্রম্পট থেকে বা একটি উত্সাহিত স্ক্রিপ্ট থেকে কাজ করে তবে সাবসেল থেকে ব্যবহৃত হলে এটি একটি ত্রুটি উত্থাপন করে:

bind: warning: line editing not enabled

পরবর্তী বর্ণিত সঠিক সমাধানটি আরও নমনীয় তবে এটি বাহ্যিক আদেশের উপর নির্ভর করে।

সঠিক সমাধান

ইনপুট ইনজেক্ট করার সঠিক উপায়টি tty_ioctl ব্যবহার করে , I / O নিয়ন্ত্রণের জন্য একটি ইউনিক্স সিস্টেম কল যার মধ্যে একটি TIOCSTIকমান্ড রয়েছে যা ইনপুট ইনজেক্ট করতে ব্যবহার করা যেতে পারে।

TIOC থেকে " টি erminal আইওসি TL " এবং STI "থেকে এস শেষ টি erminal আমি nput "।

এর জন্য কোনও আদেশই অন্তর্নিহিত হয়নি bash; এটি করার জন্য একটি বাহ্যিক আদেশ প্রয়োজন। সাধারণ জিএনইউ / লিনাক্স বিতরণে এমন কোনও কমান্ড নেই তবে সামান্য প্রোগ্রামিং সহ এটি অর্জন করা কঠিন নয় difficult এখানে একটি শেল ফাংশন রয়েছে যা ব্যবহার করে perl:

function inject() {
  perl -e 'ioctl(STDIN, 0x5412, $_) for split "", join " ", @ARGV' "$@"
}

এখানে, কমান্ডের 0x5412জন্য কোড TIOCSTI

TIOCSTIমান সহ স্ট্যান্ডার্ড সি হেডার ফাইলগুলিতে একটি ধ্রুবক সংজ্ঞায়িত 0x5412। চেষ্টা করুন grep -r TIOCSTI /usr/include, বা দেখুন /usr/include/asm-generic/ioctls.h; এটি পরোক্ষভাবে সি প্রোগ্রামগুলিতে অন্তর্ভুক্ত #include <sys/ioctl.h>

তারপরে আপনি এটি করতে পারেন:

$ inject ls -l
ls -l$ ls -l <- cursor here

কিছু অন্যান্য ভাষায় বাস্তবায়ন নীচে দেখানো হয়েছে (একটি ফাইল এবং তারপরে chmod +xএটি সংরক্ষণ করুন):

পার্ল inject.pl

#!/usr/bin/perl
ioctl(STDIN, 0x5412, $_) for split "", join " ", @ARGV

আপনি সংখ্যার মানটি ব্যবহার করার পরিবর্তে sys/ioctl.phকোনটি সংজ্ঞা দেয় তা উত্পন্ন করতে পারবেন TIOCSTIএখানে দেখুন

পাইথন inject.py

#!/usr/bin/python
import fcntl, sys, termios
del sys.argv[0]
for c in ' '.join(sys.argv):
  fcntl.ioctl(sys.stdin, termios.TIOCSTI, c)

চুনি inject.rb

#!/usr/bin/ruby
ARGV.join(' ').split('').each { |c| $stdin.ioctl(0x5412,c) }

সি inject.c

সঙ্গে সংকলন gcc -o inject inject.c

#include <sys/ioctl.h>
int main(int argc, char *argv[])
{
  int a,c;
  for (a=1, c=0; a< argc; c=0 )
    {
      while (argv[a][c])
        ioctl(0, TIOCSTI, &argv[a][c++]);
      if (++a < argc) ioctl(0, TIOCSTI," ");
    }
  return 0;
}

**! ** এখানে আরও উদাহরণ রয়েছে

এটি ব্যবহার ioctlকরে সাবস্কেলগুলিতে কাজ করে। এটি পরবর্তী ব্যাখ্যা অনুসারে অন্যান্য টার্মিনালগুলিতেও ইনজেকশন করতে পারে।

এটি আরও গ্রহণ করা (অন্যান্য টার্মিনালগুলি নিয়ন্ত্রণ করা)

এটি মূল প্রশ্নের ক্ষেত্রের বাইরে তবে উপযুক্ত অনুমতি থাকা সাপেক্ষে অন্য একটি টার্মিনালে অক্ষরগুলি ইনজেক্ট করা সম্ভব। সাধারণত এর অর্থ হচ্ছে root, তবে অন্যান্য উপায়ের জন্য নীচে দেখুন।

অন্য একটি টার্মিনালের tty নির্দিষ্ট করে একটি কমান্ড-লাইন আর্গুমেন্ট গ্রহণ করতে উপরে প্রদত্ত সি প্রোগ্রামটি বাড়ানো সেই টার্মিনালে ইনজেকশনের অনুমতি দেয়:

#include <stdlib.h>
#include <argp.h>
#include <sys/ioctl.h>
#include <sys/fcntl.h>

const char *argp_program_version ="inject - see https://unix.stackexchange.com/q/213799";
static char doc[] = "inject - write to terminal input stream";
static struct argp_option options[] = {
  { "tty",  't', "TTY", 0, "target tty (defaults to current)"},
  { "nonl", 'n', 0,     0, "do not output the trailing newline"},
  { 0 }
};

struct arguments
{
  int fd, nl, next;
};

static error_t parse_opt(int key, char *arg, struct argp_state *state) {
    struct arguments *arguments = state->input;
    switch (key)
      {
        case 't': arguments->fd = open(arg, O_WRONLY|O_NONBLOCK);
                  if (arguments->fd > 0)
                    break;
                  else
                    return EINVAL;
        case 'n': arguments->nl = 0; break;
        case ARGP_KEY_ARGS: arguments->next = state->next; return 0;
        default: return ARGP_ERR_UNKNOWN;
      }
    return 0;
}

static struct argp argp = { options, parse_opt, 0, doc };
static struct arguments arguments;

static void inject(char c)
{
  ioctl(arguments.fd, TIOCSTI, &c);
}

int main(int argc, char *argv[])
{
  arguments.fd=0;
  arguments.nl='\n';
  if (argp_parse (&argp, argc, argv, 0, 0, &arguments))
    {
      perror("Error");
      exit(errno);
    }

  int a,c;
  for (a=arguments.next, c=0; a< argc; c=0 )
    {
      while (argv[a][c])
        inject (argv[a][c++]);
      if (++a < argc) inject(' ');
    }
  if (arguments.nl) inject(arguments.nl);

  return 0;
}  

এটি ডিফল্টরূপে একটি নিউলাইনও প্রেরণ করে তবে এর মতো echoএটি -nএটি দমন করার জন্য একটি বিকল্প সরবরাহ করে। --tঅথবা --ttyবিকল্প একটি আর্গুমেন্ট প্রয়োজন - ttyটার্মিনাল ইনজেকশনের হবে। এর জন্য মানটি সেই টার্মিনালে পাওয়া যাবে:

$ tty
/dev/pts/20

এটি দিয়ে সংকলন gcc -o inject inject.c--কমান্ড-লাইন অপশনের ভুল ব্যাখ্যা করার যুক্তি পার্সারটিকে আটকানোর জন্য কোনও হাইফেন রয়েছে কিনা তা সহ পাঠ্যটিকে ইনজেক্ট করতে উপসর্গ করুন। দেখুন ./inject --help। এটি এর মতো ব্যবহার করুন:

$ inject --tty /dev/pts/22 -- ls -lrt

বা শুধু

$ inject  -- ls -lrt

বর্তমান টার্মিনাল ইনজেক্ট করতে।

অন্য টার্মিনালে ইনজেকশনের জন্য প্রশাসনিক অধিকার প্রয়োজন যা দ্বারা প্রাপ্ত করা যেতে পারে:

  • কমান্ড জারি হিসাবে root,
  • ব্যবহার sudo,
  • থাকার CAP_SYS_ADMINসামর্থ্য বা
  • এক্সিকিউটেবল সেট setuid

নিয়োগের জন্য CAP_SYS_ADMIN:

$  sudo setcap cap_sys_admin+ep inject

নিয়োগের জন্য setuid:

$ sudo chown root:root inject
$ sudo chmod u+s inject

পরিষ্কার আউটপুট

ইনজেক্টেড পাঠ্যটি প্রম্পটের সামনে উপস্থিত হয় যেন প্রম্পট প্রদর্শিত হওয়ার আগে টাইপ করা হয়েছিল (যা বাস্তবে এটি ছিল) তবে এটি প্রম্পটের পরে আবার উপস্থিত হয়।

প্রম্পটের সামনে উপস্থিত পাঠ্যটি আড়াল করার একটি উপায় হ'ল প্রের্টকে ক্যারিজ রিটার্ন দিয়ে প্রিন্ট করা ( \rলাইন-ফিড নয়) এবং বর্তমান লাইনটি সাফ করুন <ESC>[M:

$ PS1="\r\e[M$PS1"

তবে এটি কেবল সেই রেখাটি পরিষ্কার করবে যেখানে প্রম্পট প্রদর্শিত হবে। যদি ইনজেকশন করা পাঠ্যে নতুন লাইনের অন্তর্ভুক্ত থাকে তবে এটি উদ্দেশ্য হিসাবে কাজ করবে না।

অন্য একটি সমাধান ইনজেকশনের অক্ষরগুলির প্রতিধ্বনি অক্ষম করে। একটি মোড়ক এটি করতে ব্যবহার sttyকরে:

saved_settings=$(stty -g)
stty -echo -icanon min 1 time 0
inject echo line one
inject echo line two
until read -t0; do
  sleep 0.02
done
stty "$saved_settings"

যেখানে injectউপরে বর্ণিত সমাধানগুলির মধ্যে একটি, বা এর দ্বারা প্রতিস্থাপিত হয়েছে printf '\e[5n'

বিকল্প পদ্ধতি

যদি আপনার পরিবেশ নির্দিষ্ট শর্তগুলি পূরণ করে তবে আপনার কাছে অন্যান্য পদ্ধতি উপলব্ধ থাকতে পারে যা আপনি ইনপুট ইনজেক্ট করতে ব্যবহার করতে পারেন। আপনি একটি ডেস্কটপ পরিবেশে থাকেন তাহলে xdotool একটি হল X.Org উপযোগ যে মাউস এবং কীবোর্ডের কার্যকলাপ simulates কিন্তু আপনার ডিস্ট্রো এটি ডিফল্ট নাও থাকতে পারে। আপনি চেষ্টা করতে পারেন:

$ xdotool type ls

আপনি যদি টার্মিনাল মাল্টিপ্লেক্সার tmux ব্যবহার করেন তবে আপনি এটি করতে পারেন:

$ tmux send-key -t session:pane ls

যেখানে -tনির্বাচন যা অধিবেশন এবং পেন উদ্বুদ্ধ করতে। জিএনইউ স্ক্রিন এর stuffকমান্ডের সাথে একই রকম ক্ষমতা রয়েছে :

$ screen -S session -p pane -X stuff ls

যদি আপনার ডিস্ট্রোতে কনসোল-সরঞ্জাম প্যাকেজ অন্তর্ভুক্ত থাকে তবে আপনার কাছে একটি writevtআদেশ থাকতে পারে ioctlযা আমাদের উদাহরণগুলির মতো ব্যবহার করে । তবে বেশিরভাগ ডিস্ট্রো কেবিডি-র পক্ষে এই প্যাকেজটিকে অবমূল্যায়ন করেছে যা এই বৈশিষ্ট্যটির অভাব রয়েছে।

Writvt.c এর একটি আপডেট কপি ব্যবহার করে সংকলন করা যায় gcc -o writevt writevt.c

অন্যান্য ব্যবহারের ক্ষেত্রে কিছু ব্যবহারের ক্ষেত্রে উপযুক্ত হতে পারে এমন প্রত্যাশা এবং খালি অন্তর্ভুক্ত রয়েছে যা ইন্টারেক্টিভ সরঞ্জামগুলিকে স্ক্রিপ্ট করার অনুমতি দেওয়ার জন্য ডিজাইন করা হয়েছে।

আপনি এমন শেলও ব্যবহার zshকরতে পারেন যা টার্মিনাল ইনজেকশন সমর্থন করে যেমন করতে পারে print -z ls

"বাহ, সে চতুর ..." উত্তর

এখানে বর্ণিত পদ্ধতিটি এখানেও আলোচনা করা হয় এবং এখানে আলোচিত পদ্ধতিটির উপর ভিত্তি করে ।

একটি শেল পুনর্নির্দেশ করে /dev/ptmxএকটি নতুন সিউডো-টার্মিনাল পায়:

$ $ ls /dev/pts; ls /dev/pts </dev/ptmx
0  1  2  ptmx
0  1  2  3  ptmx

সি তে লেখা একটি ছোট্ট সরঞ্জাম যা সিউডোটারমিনাল মাস্টার (পিটিএম) কে আনলক করে এবং সিউডোটার্মিনাল ক্রীতদাস (পিটিএস) এর নামটিকে তার স্ট্যান্ডার্ড আউটপুটে আউটপুট করে।

#include <stdio.h>
int main(int argc, char *argv[]) {
    if(unlockpt(0)) return 2;
    char *ptsname(int fd);
    printf("%s\n",ptsname(0));
    return argc - 1;
}

(হিসাবে সংরক্ষণ করুন pts.cএবং এর সাথে সংকলন gcc -o pts pts.c)

প্রোগ্রামটি যখন কোনও ptm এ স্ট্যান্ডার্ড ইনপুট সেট করে ডাকা হয় তখন এটি সংশ্লিষ্ট পিটিগুলি আনলক করে এবং স্ট্যান্ডার্ড আউটপুটে এর নাম আউটপুট করে।

$ ./pts </dev/ptmx
/dev/pts/20
  • Unlockpt () ফাংশন ক্রীতদাস pseudoterminal ডিভাইস মাস্টার pseudoterminal দেওয়া ফাইল বর্ণনাকারী দ্বারা উল্লেখ করা সংশ্লিষ্ট আনলক হয়ে যাবে। প্রোগ্রামটি শূন্য হিসাবে পাস করে যা প্রোগ্রামটির মানক ইনপুট

  • Ptsname () ফাংশন আয় ক্রীতদাস pseudoterminal ডিভাইস মাস্টার আনুসঙ্গিক নাম দেওয়া ফাইল বর্ণনাকারী দ্বারা উল্লেখ করা হয়েছে, আবার প্রোগ্রামের মান ইনপুট জন্য শূন্য ক্ষণস্থায়ী।

একটি প্রক্রিয়া pts সংযুক্ত করা যেতে পারে। প্রথমে একটি পিটিএম পান (এখানে এটি ফাইল বর্ণনাকারী 3 অর্পণ করা হয়েছে, <>পুনর্নির্দেশের দ্বারা পঠন-লিখন খোলা হয়েছে )।

 exec 3<>/dev/ptmx

তারপরে প্রক্রিয়াটি শুরু করুন:

$ (setsid -c bash -i 2>&1 | tee log) <>"$(./pts <&3)" 3>&- >&0 &

এই কমান্ড-লাইন দ্বারা উদ্ভূত প্রক্রিয়াগুলি এর সাথে সর্বোত্তম চিত্রিত pstree:

$ pstree -pg -H $(jobs -p %+) $$
bash(5203,5203)─┬─bash(6524,6524)─┬─bash(6527,6527)
                             └─tee(6528,6524)
            └─pstree(6815,6815)

আউটপুট বর্তমান শেল ( $$) এর সাথে সম্পর্কিত এবং প্রতিটি প্রক্রিয়াটির পিআইডি ( -p) এবং পিজিআইডি ( -g) বন্ধনীতে দেখানো হয়েছে (PID,PGID)

গাছের bash(5203,5203)শিরোনামে, ইন্টারেক্টিভ শেল যেটিতে আমরা কমান্ডগুলি টাইপ করছি এবং এর ফাইল বর্ণনাকারীরা এটি টার্মিনাল অ্যাপ্লিকেশনের সাথে সংযুক্ত করে আমরা এটির ( xtermবা অনুরূপ) সাথে ইন্টারেক্ট করার জন্য ব্যবহার করছি ।

$ ls -l /dev/fd/
lrwx------ 0 -> /dev/pts/3
lrwx------ 1 -> /dev/pts/3
lrwx------ 2 -> /dev/pts/3

কমান্ডটি আবার দেখলে, প্রথম বন্ধনীগুলির প্রথম সেটটি সাবসেল শুরু করেছিল, bash(6524,6524)যার ফাইল ডেস্ক্রিপ্টার 0 (এর স্ট্যান্ডার্ড ইনপুট ) পিটিএসকে দেওয়া হয়েছিল (যা রিডিং-রাইট খোলা হয় <>) অন্য আনুষাঙ্গিকে ./pts <&3আনলক করার জন্য কার্যকর করা হয়েছিল পিটিএস ফাইল বর্ণনাকারী 3 (পূর্ববর্তী ধাপে তৈরি, exec 3<>/dev/ptmx) এর সাথে সম্পর্কিত।

সাবশেলের ফাইল ডেস্ক্রিপ্টর 3 টি বন্ধ ( 3>&-) যাতে পিটিএম এর কাছে অ্যাক্সেসযোগ্য না থাকে। এর স্ট্যান্ডার্ড ইনপুট (এফডি 0), যা পড়তে / লেখার জন্য খোলা pts, এটি >&0তার স্ট্যান্ডার্ড আউটপুট (এফডি 1) এ পুনঃনির্দেশিত হয় (আসলে fd অনুলিপি করা হয় )।

এটি পিটিএসের সাথে সংযুক্ত তার স্ট্যান্ডার্ড ইনপুট এবং আউটপুট সহ একটি সাবশেল তৈরি করে। এটি পিটিএম লিখে লিখে ইনপুট প্রেরণ করা যায় এবং পিটিএম থেকে পড়ে এর আউটপুটটি দেখা যায়:

$ echo 'some input' >&3 # write to subshell
$ cat <&3               # read from subshell

সাবশেল এই আদেশটি কার্যকর করে:

setsid -c bash -i 2>&1 | tee log

এটি একটি নতুন সেশনে bash(6527,6527)ইন্টারেক্টিভ ( -i) মোডে setsid -cচলবে ( , নোট করুন পিআইডি এবং পিজিআইডি একই রকম)। এটির স্ট্যান্ডার্ড ত্রুটিটি তার স্ট্যান্ডার্ড আউটপুট ( 2>&1) এ পুনঃনির্দেশিত হয় এবং পাইপ করা হয় tee(6528,6524)যাতে এটি কোনও logফাইলে এবং পিটিএসে লেখা থাকে। এটি সাবসেলের আউটপুটটি দেখার আরও একটি উপায় দেয়:

$ tail -f log

সাবসেল bashইন্টারেক্টিভভাবে চলমান হওয়ায় , এটি কার্যকর করার জন্য কমান্ড প্রেরণ করা যেতে পারে, উদাহরণস্বরূপ যা সাবশেলের ফাইল বর্ণনাকারীদের প্রদর্শন করে:

$ echo 'ls -l /dev/fd/' >&3

সাবশেলের আউটপুট ( tail -f logবা cat <&3) পড়ার বিষয়টি প্রকাশ করে:

lrwx------ 0 -> /dev/pts/17
l-wx------ 1 -> pipe:[116261]
l-wx------ 2 -> pipe:[116261]

স্ট্যান্ডার্ড ইনপুট (এফডি 0) পিটিএসের সাথে সংযুক্ত এবং স্ট্যান্ডার্ড আউটপুট (এফডি 1) এবং ত্রুটি (এফডি 2) উভয়ই একই পাইপের সাথে সংযুক্ত রয়েছে, এটি যা সংযোগ করে tee:

$ (find /proc -type l | xargs ls -l | fgrep 'pipe:[116261]') 2>/dev/null
l-wx------ /proc/6527/fd/1 -> pipe:[116261]
l-wx------ /proc/6527/fd/2 -> pipe:[116261]
lr-x------ /proc/6528/fd/0 -> pipe:[116261]

এবং ফাইল বর্ণনাকারী এক নজরে tee

$ ls -l /proc/6528/fd/
lr-x------ 0 -> pipe:[116261]
lrwx------ 1 -> /dev/pts/17
lrwx------ 2 -> /dev/pts/3
l-wx------ 3 -> /home/myuser/work/log

স্ট্যান্ডার্ড আউটপুট (এফডি 1) হ'ল পিটিএস: 'টি' তার স্ট্যান্ডার্ড আউটপুটটিতে যে কোনও কিছুই লিখে দেয় তা পিটিএম এ ফিরে পাঠানো হয়। স্ট্যান্ডার্ড ত্রুটি (এফডি 2) হ'ল নিয়ন্ত্রণকারী টার্মিনালের অন্তর্গত pts।

এটিকে গুটিয়ে রাখা

নীচের স্ক্রিপ্ট উপরে বর্ণিত কৌশল ব্যবহার করে। এটি একটি ইন্টারেক্টিভ bashসেশন সেট আপ করে যা কোনও ফাইল বর্ণনাকারীর কাছে লিখে সংক্রামিত হতে পারে। এটি এখানে উপলব্ধ এবং ব্যাখ্যা সহ নথিভুক্ত।

sh -cm 'cat <&9 &cat >&9|(             ### copy to/from host/slave
        trap "  stty $(stty -g         ### save/restore stty settings on exit
                stty -echo raw)        ### host: no echo and raw-mode
                kill -1 0" EXIT        ### send a -HUP to host pgrp on EXIT
        <>"$($pts <&9)" >&0 2>&1\
        setsid -wc -- bash) <&1        ### point bash <0,1,2> at slave and setsid bash
' --    9<>/dev/ptmx 2>/dev/null       ### open pty master on <>9

সবচেয়ে সহজ পদ্ধিতি হল সঙ্গে bind '"\e[0n": "ls -l"'; printf '\e[5n'সমাধান, সব আউটপুট পর ls -lএছাড়াও ^[[0nটার্মিনাল উপর outputted করা হবে না একবার আমি Enter কী এইভাবে চালানো আঘাত ls -l। কোনও ধারণা কীভাবে এটি "লুকিয়ে" রাখবেন? ধন্যবাদ.
আলী

1
আমি একটি সমাধান উপস্থাপন করেছি যা আপনার পরে প্রভাবটি দেয় - আমার উত্তরের পরিষ্কার আউটপুট বিভাগে আমি উত্সাহী পাঠ্যটি আড়াল করার জন্য প্রম্পটে ফিরে আসার পরামর্শ দিই। আমি করার PS1="\r\e[M$PS1"আগে চেষ্টা করেছিলাম bind '"\e[0n": "ls -l"'; printf '\e[5n'এবং এটি আপনার বর্ণনার প্রভাব দেয়।
স্টারফ্রি

ধন্যবাদ! আমি পুরোপুরি এই পয়েন্টটি মিস করেছি।
আলী

20

এটি bashকেবলমাত্র আপনি কী বোঝাতে চান তার উপর নির্ভর করে । আপনি যদি একটি একক, ইন্টারেক্টিভ bashসেশনটি বোঝাতে চান তবে উত্তরটি অবশ্যই অবশ্যই না । এবং এটি কারণ আপনি যখন ls -lকোনও ক্যানোনিকাল টার্মিনালের কমান্ড-লাইনের মতো একটি কমান্ড প্রবেশ করেন bashতখনও এটি সম্পর্কে অবগতও হয় না - এবং bashএমনকি এই পর্যায়ে জড়িতও না।

বরং, এখন পর্যন্ত যা ঘটেছে তা হ'ল কার্নেলের tty লাইন-শৃঙ্খলাটি stty echoকেবলমাত্র পর্দায় ব্যবহারকারীর ইনপুটটি বাফার করেছে । এটি তার পাঠকের কাছে এই ইনপুটটিকে ফ্লাশ করে - bashআপনার উদাহরণের ক্ষেত্রে - লাইন দ্বারা লাইন - এবং সাধারণত ইউনিক্স সিস্টেমগুলিতে ইটলাইনগুলিতে পাশাপাশি অনুবাদ করে - এবং তাই না - এবং তাই আপনার উত্সাহিত লিপিটিও - সচেতন করা যায় না যে কোনও আছে ব্যবহারকারী কী টিপুন যতক্ষণ না ইনপুট ।\r\nbashENTER

এখন, কিছু কাজ প্রায় আছে। সর্বাধিক শক্তিশালী মোটেও কোনও পরিশ্রমের কাজ নয়, এবং ইনপুট অনুক্রমের জন্য একাধিক প্রক্রিয়া বা বিশেষভাবে লিখিত প্রোগ্রামগুলি -echoব্যবহার করা, ব্যবহারকারীর কাছ থেকে লাইন-শৃঙ্খলাটি আড়াল করা এবং ইনপুট ব্যাখ্যা করার সময় কেবল উপযুক্ত স্ক্রিনে লিখুন বিশেষত যখন প্রয়োজন। এটি ভালভাবে করা কঠিন হতে পারে কারণ এর অর্থ এমন ব্যাখ্যার বিধিগুলি লিখুন যা এলোমেলো ইনপুট চরটি আসার সাথে সাথে পরিচালনা করতে পারে এবং সেই পরিস্থিতিতে গড় ব্যবহারকারী কী প্রত্যাশা করবে তা অনুকরণ করার জন্য ভুল ছাড়াই একযোগে এটি লিখে দেওয়া। এই কারণেই সম্ভবত এটি ইন্টারেক্টিভ টার্মিনাল i / o খুব কমই ভালভাবে বোঝা যায় - এমন সম্ভাবনা খুব কঠিন নয় যে নিজেকে বেশিরভাগ তদন্তের জন্য ধার দেয়।

আর একটি কাজ চারপাশে টার্মিনাল এমুলেটর জড়িত হতে পারে। আপনি বলেছেন যে আপনার জন্য একটি সমস্যা এক্স এবং তার উপর নির্ভরতা xdotool। সেক্ষেত্রে যেমন প্রস্তাবিত কাজটি করতে চলেছি তেমন সমস্যা থাকতে পারে তবে আমি এটির সাথে একইভাবে এগিয়ে যাব।

printf  '\33[22;1t\33]1;%b\33\\\33[20t\33[23;0t' \
        '\025my command'

এটি একটি xtermডাব্লু / allowwindowOpsরিসোর্স সেটে কাজ করবে । এটি প্রথমে স্ট্যাকের মধ্যে আইকন / উইন্ডোর নামগুলি সংরক্ষণ করে, তারপরে টার্মিনালের আইকন-স্ট্রিং সেট করে ^Umy commandতারপরে অনুরোধ করে যে টার্মিনাল সেই নামটিকে ইনপুট সারিতে ইনজেক্ট করে, এবং শেষ পর্যন্ত এটি সংরক্ষিত মানগুলিতে পুনরায় সেট করে। ডাব্লু / ডান কনফিগারেশনে bashচালিত ইন্টারেক্টিভ শেলগুলির জন্য এটি অদৃশ্যভাবে কাজ করা উচিত - xtermতবে এটি সম্ভবত একটি খারাপ ধারণা। নীচে স্টাফেনের মন্তব্য দেখুন।

যদিও, printfআমার মেশিনে বিট ডাব্লু / অন্যরকম পালানোর ক্রম চালানোর পরে আমি আমার টার্মিনোলজি টার্মিনালের একটি ছবি তুলেছি। প্রতিটি সম্পর্কে newline জন্য printfকমান্ড আমি টাইপ করা CTRL+Vতারপর CTRL+Jএবং পরে চাপা ENTERকী। পরে আমি কিছুই টাইপ করি নি, তবে, আপনি দেখতে পাচ্ছেন, টার্মিনালটি my commandআমার জন্য লাইন-শৃঙ্খলার ইনপুট সারিতে ইনজেক্ট করা হয়েছে:

term_inject

এটি করার আসল উপায় হ'ল ডাব্লু / নেস্টেড পিটিআই। এটি কীভাবে screenএবং tmuxঅনুরূপ কাজ - উভয়ই, যাইহোক, এটি আপনার পক্ষে সম্ভব করে তুলতে পারে। xtermআসলে একটি সামান্য প্রোগ্রাম বলা হয় luitযা এটি এটি সম্ভব করে তুলতে পারে। যদিও এটি সহজ নয়।

এখানে আপনি যা করতে পারেন তার একটি উপায়:

sh -cm 'cat <&9 &cat >&9|(             ### copy to/from host/slave
        trap "  stty $(stty -g         ### save/restore stty settings on exit
                stty -echo raw)        ### host: no echo and raw-mode
                kill -1 0" EXIT        ### send a -HUP to host pgrp on EXIT
        <>"$(pts <&9)" >&0 2>&1\       
        setsid -wc -- bash) <&1        ### point bash <0,1,2> at slave and setsid bash
' --    9<>/dev/ptmx 2>/dev/null       ### open pty master on <>9

এটি কোনওভাবেই পোর্টেবল নয়, তবে বেশিরভাগ লিনাক্স সিস্টেমে খোলার জন্য যথাযথ অনুমতি দেওয়া উচিত /dev/ptmx। আমার ব্যবহারকারী ttyগ্রুপে রয়েছে যা আমার সিস্টেমে যথেষ্ট। আপনারও দরকার হবে ...

<<\C cc -xc - -o pts
#include <stdio.h>
int main(int argc, char *argv[]) {
        if(unlockpt(0)) return 2;
        char *ptsname(int fd);
        printf("%s\n",ptsname(0));
        return argc - 1;
}
C

... যা, যখন কোনও জিএনইউ সিস্টেমে চালিত হয় (বা স্ট্যান্ডিন থেকে পড়া স্ট্যান্ডার্ড সি সংকলক সহ অন্য কোনও) , তখন একটি ছোট এক্সিকিউটেবল বাইনারি লিখবে যা তার স্টিডিনে ফাংশনটি পরিচালনা ptsকরবে unlockpt()এবং তার স্টাডআউটে লিখবে এটি কেবল আনলক করা পিটিআই ডিভাইসের নাম। কাজ করার সময় আমি এটি লিখেছিলাম ... আমি এই পিটিআই দ্বারা কীভাবে আসব এবং আমি এটি দিয়ে কী করতে পারি?

যাইহোক, উপরের বিট কোডটি যা করে তা হ'ল bashবর্তমান টিটিটির নীচে একটি লেয়ারে একটি শেল চালায় । bashদাস পিটিআই-তে সমস্ত আউটপুট লিখতে বলা হয়েছিল এবং বর্তমান টিটি উভয়ই -echoএটির ইনপুট না বা এটি বাফার করার জন্য কনফিগার করা হয়েছে, পরিবর্তে এটি (বেশিরভাগ ক্ষেত্রে) পাস rawকরার জন্য cat, যা এটি অনুলিপি করে bash। এবং অন্যদিকে, ব্যাকগ্রাউন্ডে catসমস্ত দাস আউটপুট বর্তমান টিটির কাছে অনুলিপি করে।

মূলত শুধু অপ্রয়োজনীয়, - - অধিকাংশ অংশ জন্য উপরে কনফিগারেশন সম্পূর্ণরূপে বেহুদা হবে ব্যতীত যে আমরা আরম্ভ bashউপর নিজস্ব Pty মাস্টার FD একটি কপি সঙ্গে <>9। এর অর্থ এটি bashএকটি সাধারণ পুনঃনির্দেশের সাহায্যে অবাধে নিজের ইনপুট স্ট্রিমে লিখতে পারে। যা bashকরতে হবে তা হ'ল:

echo echo hey >&9

... নিজের সাথে কথা বলার জন্য।

এখানে অন্য একটি ছবি:

এখানে চিত্র বর্ণনা লিখুন


2
আপনি কোন টার্মিনালগুলিতে এটি কাজ করতে পরিচালিত করেছেন? পুরানো দিনগুলিতে এই জাতীয় জিনিসটির অপব্যবহার করা হয়েছিল এবং আজকাল ডিফল্টরূপে এটি অক্ষম করা উচিত। এর সাথে xterm, আপনি এখনও আইকন শিরোনামটি দিয়ে জিজ্ঞাসা করতে পারেন \e[20tতবে কেবল এটির সাথে কনফিগার করা থাকলে allowWindowOps: true
স্টাফেন চেজেলাস


@ স্টাফেনচেজেলাস যা টার্মিনোলজিতে কাজ করে, তবে আমি নিশ্চিত যে এটি জিনোম টার্মিনালে, কেডি টার্মিনালেও কাজ করে (আমি এর নামটি ভুলে গিয়েছি , এবং আমার মনে হয় এর থেকে আলাদা পালাতে পারে) , এবং আপনি যেমন বলছেন, ডাব্লু / xtermডাব্লু / যথাযথ কনফিগ। ডাব্লু / একটি এক্সটার্ম যথাযথ, যদিও আপনি কপি / পেস্ট বাফারটি পড়তে এবং লিখতে পারেন এবং এটি আরও সহজ হয়ে ওঠে, আমি মনে করি। এক্সটার্মের শর্তাদির বিবরণটিই পরিবর্তিত / প্রভাবিত করার জন্য পালানোর ক্রম রয়েছে।
মাইক্রজারভ

আমি এটি পরিভাষা ব্যতীত অন্য কোনও ক্ষেত্রে কাজ করতে পারি না (যা বিটিডব্লিউতে বিভিন্ন ধরণের অন্যান্য দুর্বলতা রয়েছে)। সেই সিভিই 12 বছরেরও বেশি বয়সী এবং তুলনামূলকভাবে সুপরিচিত যে আমি যদি প্রধান টার্মিনাল এমুলেটরটির দু'জনের একই দুর্বলতা থাকে তবে আমি অবাক হব। দ্রষ্টব্য যে এক্সটার্মের সাথে, এটি \e[20t(নয় \e]1;?\a)
স্টাফেন চেজেলাস


8

যদিও স্টাফেন চেজেলাসের ioctl(,TIOCSTI,) উত্তর অবশ্যই সঠিক উত্তর, কিছু লোক এই আংশিক কিন্তু তুচ্ছ উত্তর দিয়ে যথেষ্ট খুশি হতে পারে: কেবল ইতিহাসের স্ট্যাকের উপর কমান্ডটি চাপুন, তারপরে ব্যবহারকারী ইতিহাসটি সন্ধানের জন্য 1 লাইন উপরে স্থানান্তর করতে পারবেন কমান্ড।

$ history -s "ls -l"
$ echo "move up 1 line in history to get command to run"

এটি একটি সাধারণ স্ক্রিপ্টে পরিণত হতে পারে, যার নিজস্ব 1 লাইনের ইতিহাস রয়েছে:

#!/bin/bash
history -s "ls -l"
read -e -p "move up 1 line: "
eval "$REPLY"

read -eইনপুটটির রিডলাইন সম্পাদনা সক্ষম করে, -pএটি একটি প্রম্পট।


এটি কেবল শেল ফাংশনগুলিতেই কাজ করবে, বা যদি স্ক্রিপ্টটি উত্সাহিত করা হয়েছিল ( . foo.shবা `উত্স foo.sh, সাবসেল চালানোর পরিবর্তে)) আকর্ষণীয় পন্থা, যদিও। অনুরূপ হ্যাকের জন্য যা কলিং শেলের প্রসঙ্গটি সংশোধন করা দরকার তা হ'ল একটি কাস্টম সমাপ্তি সেট আপ করা যা খালি রেখাটিকে কিছুতে প্রসারিত করে এবং তারপরে পুরানো সমাপ্তি হ্যান্ডলারটি পুনরুদ্ধার করে।
পিটার কর্ডেস

@ পিটারকর্ডস আপনি ঠিক বলেছেন আমি প্রশ্নটি খুব আক্ষরিকভাবে নিচ্ছিলাম। তবে আমি কাজ করতে পারি এমন একটি সাধারণ স্ক্রিপ্টের উদাহরণ যুক্ত করেছি।
meuh

@ মিকসার্ভ হেই, এটির একটি সহজ সমাধান যা কিছু লোকের পক্ষে কার্যকর হতে পারে। evalপাইপ এবং পুনঃনির্দেশ ইত্যাদি ছাড়াই আপনার সম্পাদনা করার সহজ কমান্ড থাকলে এমনকি আপনি মুছে ফেলতে পারেন
meuh

1

ওহে আমার কথা, বাশ দেওয়ার জন্য আমরা একটি অন্তর্নির্মিত সহজ সমাধানটি হাতছাড়া করেছি : readকমান্ডের একটি বিকল্প রয়েছে -i ..., যা যখন ব্যবহৃত হয় তখন -eপাঠ্যটিকে ইনপুট বাফারে ঠেলে দেয়। ম্যান পৃষ্ঠা থেকে:

-i পাঠ্য

লাইনটি পড়তে যদি রিডলাইন ব্যবহার করা হয়, সম্পাদনা শুরুর আগে পাঠ্য সম্পাদনা বাফারে স্থাপন করা হয়।

সুতরাং একটি ছোট বাশ ফাংশন বা শেল স্ক্রিপ্ট তৈরি করুন যা ব্যবহারকারীর সামনে উপস্থাপনের জন্য কমান্ড নেয় এবং তাদের উত্তরটি চালায় বা মূল্যায়ন করে:

domycmd(){ read -e -i "$*"; eval "$REPLY"; }

এটি সন্দেহাতীতভাবে ioctl (, TIOCSTI) ব্যবহার করে যা প্রায় 32 বছরেরও বেশি সময় ধরে রয়েছে, কারণ এটি ইতিমধ্যে 2.9BSD ioctl.h তে বিদ্যমান ছিল ।


1
অনুরূপ প্রভাব সহ আকর্ষণীয় একটি, তবে এটি প্রম্পটে যদিও ইনজেকশন দেয় না।
স্টারফাই

2 য় চিন্তা আপনি সঠিক। বাশকে টিআইওএসটিআইয়ের দরকার নেই কারণ এটি সমস্ত i / o নিজেই করছে।
meuh
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.