교류가 가능한가요?세게 때리다쉘은 사용자가 해당 프롬프트에서 해당 텍스트를 입력한 것처럼 다음 명령 프롬프트에 나타나도록 일부 텍스트를 출력하는 명령을 입력합니까?
source
스크립트가 명령줄을 생성하고 스크립트가 끝난 후 프롬프트가 반환될 때 나타나도록 출력하여 사용자가 enter
실행하기 전에 편집 하도록 선택할 수 있도록 하고 싶습니다 .
이는 다음과 같은 방법으로 달성할 수 있지만 xdotool
터미널이 X 창에 있고 설치된 경우에만 가능합니다.
[me@mybox] 100 $ xdotool type "ls -l"
[me@mybox] 101 $ ls -l <--- cursor appears here!
bash 만 사용하여 이것이 가능합니까?
답변1
를 사용하면 다음 프롬프트를 위해 줄 편집기 버퍼에 일부 텍스트를 넣을 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
터미널로부터 수신된 것처럼 터미널 장치 입력 버퍼에 삽입됩니다 .
더 많은 휴대용 변형@mike의 Terminology
방법query status report
그리고 보안을 희생하지 않고 상당히 표준적인 이스케이프 시퀀스를 터미널 에뮬레이터로 보내는 것입니다 . <ESC>[5n
터미널은 항상 입력으로 응답 <ESC>[0n
하고 삽입하려는 문자열에 바인딩합니다.
bind '"\e[0n": "echo test"'; printf '\e[5n'
GNU 내부에서는 screen
다음을 수행할 수도 있습니다.
screen -X stuff 'echo test'
이제 TIOCSTI ioctl 메소드 외에도 터미널 에뮬레이터에 입력한 것처럼 일부 문자열을 보내도록 요청합니다. 이 문자열은 터미널 로컬 에코가 비활성화되기 전에 나타나는 경우 표시됩니다 readline
( 라인 편집기에서).bash
아니요쉘 프롬프트에서 디스플레이가 약간 엉망이 됩니다.
이 문제를 해결하려면, readline이 에코를 비활성화할 때 응답이 도착하도록 터미널로의 요청 전송을 약간 지연시킬 수 있습니다.
bind '"\e[0n": "echo test"'; ((sleep 0.05; printf '\e[5n') &)
(이는 sleep
1초 미만의 해상도를 지원한다고 가정합니다.)
이상적으로는 다음과 같은 작업을 수행하고 싶습니다.
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"
추가 읽기
바라보다@starfry의 답변이는 @mikeserv와 나 자신이 제공한 두 가지 솔루션을 확장하고 좀 더 자세한 내용을 제공합니다.
답변2
이 답변은 나보다 먼저 온 @StéphaneChazelas와 @mikeserv로부터 영감을 받아 내 자신의 이해를 명확히하기 위해 제공됩니다.
긴 이야기 짧게
bash
이것은 외부의 도움 없이는 불가능합니다.- 올바른 방법은터미널 입력 보내기
ioctl
하지만 - 가장 간단한 가능한
bash
솔루션이 사용됩니다bind
.
간단한 해결책
bind '"\e[0n": "ls -l"'; printf '\e[5n'
bind
Bash 에는 키 시퀀스가 수신될 때 쉘 명령이 실행될 수 있도록 하는 쉘이라는 내장 명령이 있습니다 . 기본적으로 쉘 명령의 출력은 쉘의 입력 버퍼에 기록됩니다.
$ bind '"\e[0n": "ls -l"'
key_sequence \e[0n
( <ESC>[0n
)는ANSI 터미널 이스케이프 코드터미널이 제대로 작동하고 있음을 나타내기 위해 터미널에서 보냅니다. 이에 대한 응답으로 이 메시지를 보냅니다.장치 상태 보고 요청.<ESC>[5n
삽입할 텍스트를 출력하는 응답 에 응답을 바인딩하면 echo
장치 상태를 요청하여 언제든지 해당 텍스트를 삽입할 수 있으며, 이 작업은 <ESC>[5n
이스케이프 시퀀스를 전송하여 수행됩니다.
printf '\e[5n'
다른 도구가 포함되어 있지 않기 때문에 이것은 작동하며 원래 질문에 대답하기에 충분할 수 있습니다. 순수 bash
하지만 제대로 작동하는 터미널에 의존합니다(거의 모든 터미널이 그렇습니다).
입력한 그대로 명령줄에 에코된 텍스트를 사용할 수 있도록 남겨둡니다. 를 누르면 추가, 편집, ENTER
실행이 가능합니다.
\n
자동으로 실행되도록 하려면 바인딩 명령에 추가하세요 .
그러나 이 솔루션은 현재 터미널에서만 작동합니다(원래 질문의 범위 내에서). 대화형 프롬프트나 다음을 통해 수행할 수 있습니다.원천스크립트이지만 서브셸에서 사용하면 오류가 발생합니다.
bind: warning: line editing not enabled
올바른 솔루션다음에 설명하는 내용은 더 유연하지만 외부 명령에 의존합니다.
올바른 솔루션
입력을 주입하는 올바른 방법은 다음을 사용하는 것입니다.tty_ioctl, UNIX 시스템 호출입출력 제어TIOCSTI
입력을 주입하는 데 사용할 수 있는 명령이 있습니다 .
티타늄 오크에서"시간단말기국제 올림픽 위원회전화" 그리고성병에서"에스끝시간단말기나입력하다".
bash
이를 위한 내장 명령 은 없습니다 . 이를 위해서는 외부 명령이 필요합니다. 일반적인 GNU/Linux 배포판에는 그러한 명령이 없지만 일부 프로그래밍으로 구현하는 것은 어렵지 않습니다. 이는 다음 명령을 사용하는 쉘 함수입니다 perl
.
function inject() {
perl -e 'ioctl(STDIN, 0x5412, $_) for split "", join " ", @ARGV' "$@"
}
이것은 0x5412
명령에 대한 코드입니다 TIOCSTI
.
TIOCSTI
는 표준 C 헤더 파일에 정의된 상수입니다 0x5412
. 직접 사용해 보거나 C 프로그램에 간접적으로 포함되어 있는지 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
이를 수행하려면 서브쉘을 사용하십시오 . 아래에 설명된 대로 다른 터미널에 주입할 수도 있습니다.
더 나아가기(다른 터미널 제어)
원래 질문의 범위를 벗어나지만 다른 터미널에 문자를 삽입하는 것은 가능하지만 적절한 권한이 필요합니다. 일반적으로 이는 yes 를 의미 root
하지만, 다른 방법은 아래를 참조하세요.
위에 제공된 C 프로그램을 확장하여 다른 터미널 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
제공합니다 . or 옵션에는 하나의 인수( 삽입할 터미널)가 필요합니다. 이 터미널에서 값을 얻을 수 있습니다.-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'
.
대체 방법
환경이 특정 전제 조건을 충족하는 경우 다른 방법을 사용하여 입력을 주입할 수 있습니다. 데스크탑 환경인 경우xdo 도구는X 조직마우스 및 키보드 활동을 시뮬레이션하는 유틸리티이지만 배포판에는 기본적으로 포함되지 않을 수 있습니다. 당신은 시도 할 수 있습니다:
$ xdotool type ls
당신이 사용하는 경우멀티플렉서, 터미널 멀티플렉서를 사용하면 다음을 수행할 수 있습니다.
$ tmux send-key -t session:pane ls
어느 것을 -t
선택할 것인가회의그리고창유리주입.GNU 화면해당 명령에는 비슷한 기능이 있습니다 stuff
.
$ screen -S session -p pane -X stuff ls
배포판에 다음이 포함된 경우콘솔 도구그러면 우리의 예처럼 writevt
사용할 명령이 있을 수 있습니다. ioctl
그러나 대부분의 배포판에서는 이 패키지를 더 이상 사용하지 않습니다.지식 기반이 기능이 없습니다.
업데이트된 사본vt.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
의사 터미널 마스터(ptm)의 잠금을 해제하고 의사 터미널 슬레이브(pts)의 이름을 표준 출력에 인쇄하는 C로 작성된 작은 도구입니다.
#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으로 설정되면 해당 pt의 잠금을 해제하고 해당 이름을 표준 출력에 인쇄합니다.
$ ./pts </dev/ptmx
/dev/pts/20
이것pt() 잠금해제 함수는 주어진 파일 설명자가 참조하는 마스터 의사 터미널에 해당하는 슬레이브 의사 터미널 장치의 잠금을 해제합니다. 프로그램은 이를 nil로 전달하는데, 이는 프로그램의표준 입력.
이것점호() 이 함수는 주어진 파일 설명자가 참조하는 마스터 장치에 해당하는 슬레이브 의사 터미널 장치의 이름을 반환하고 프로그램의 표준 입력에 대해 다시 0을 전달합니다.
프로세스는 포인트에 연결할 수 있습니다. 먼저 ptm을 얻습니다(여기서는 파일 설명자 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)
출력은 현재 쉘( $$
)을 기준으로 하며 각 프로세스의 PID( -p
) 및 PGID( -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(이전 단계에서 생성됨)과 연관된 pts 잠금 해제를 수행하는 다른 서브쉘(읽기 및 쓰기를 위해 열림)에 의해 반환된 pts에 할당됩니다 exec 3<>/dev/ptmx
.
서브쉘의 파일 디스크립터 3이 닫혀( 3>&-
) 있으므로 ptm에 접근할 수 없습니다. 읽기/쓰기를 위해 열린 pts인 표준 입력(fd 0)은 >&0
표준 출력(fd 1)으로 리디렉션됩니다(실제로 fd는 복사됩니다 - ).
그러면 표준 입력 및 출력이 pts에 연결된 하위 쉘이 생성됩니다. 입력은 ptm에 작성하여 보낼 수 있으며 출력은 ptm에서 읽어 볼 수 있습니다.
$ echo 'some input' >&3 # write to subshell
$ cat <&3 # read from subshell
Subshell은 다음 명령을 실행합니다.
setsid -c bash -i 2>&1 | tee log
새 세션에서는 대화형( ) 모드로 실행됩니다 bash(6527,6527)
(PID와 PGID는 동일함). 표준 오류는 표준 출력( )으로 리디렉션되고 파이프되어 파일과 pts에 기록됩니다. 이는 서브셸 출력을 보는 또 다른 방법을 제공합니다.-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]
표준 입력(fd 0)은 pts에 연결되고, 표준 출력(fd 1)과 오류(fd 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
표준 출력(fd 1)은 pts입니다. "tee"가 표준 출력에 쓰는 모든 내용은 ptm으로 다시 전송됩니다. 표준 오류(fd 2)는 제어 터미널에 속하는 지점입니다.
마무리하다
다음 스크립트는 위의 기술을 사용합니다. 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
답변3
그건 당신이 무슨 뜻인지에 따라 달라요bash
오직. 단일 대화형 세션을 언급하는 경우 bash
대답은 거의 확실합니다.아니요. ls -l
이는 표준 터미널의 명령줄에 명령을 입력 하더라도 bash
이를 인식하지 못할 뿐 아니라 bash
당시에는 해당 명령에 관여하지도 않기 때문입니다.
대신, 지금까지 일어난 일은 커널의 tty 라인 규칙이 stty echo
사용자의 입력을 버퍼링하여 화면에만 보낸 것입니다. bash
귀하의 예에서는 한 줄씩 입력을 판독기에게 플러시 하고 일반적으로 Unix 시스템에서는 \r
반환을 ewlines로 변환하므로 입력이 진행 중이라는 것을 알 수 없으므로 소스 스크립트는 알 수 없습니다. , 사용자가 누를 때까지\n
bash
ENTER
열쇠.
이제 몇 가지 해결책이 있습니다. 실제로 가장 강력한 방법은 해결 방법이 전혀 아니지만 여러 프로세스나 특별히 작성된 프로그램을 사용하여 입력을 정렬하고, 사용자에게 줄 규칙을 숨기고 -echo
, 입력을 해석할 때 적절하다고 판단되는 것만 화면에 기록하는 것입니다. 특히 필요한 경우. 이는 임의의 입력 문자가 도착할 때 이를 처리하고 동시에 오류 없이 작성할 수 있는 해석 규칙을 작성하여 해당 시나리오에서 일반 사용자가 기대하는 것을 시뮬레이션하기 때문에 잘 수행하기 어려울 수 있습니다. 아마도 이런 이유 때문에 대화형 터미널 I/O는 잘 이해되지 않습니다. 대부분의 사람들에게 이 어려운 전망은 더 이상 연구할 수 없습니다.
또 다른 해결 방법에는 터미널 에뮬레이터가 포함될 수 있습니다. 문제가 X 및 xdotool
. 이런 경우 제가 제공하려는 해결 방법도 비슷한 문제를 겪을 수 있지만, 어쨌든 계속 해보겠습니다.
printf '\33[22;1t\33]1;%b\33\\\33[20t\33[23;0t' \
'\025my command'
이것은 xterm
다음과 함께 작동합니다allowwindowOps
자원 세트. 먼저 아이콘/창 이름을 스택에 저장한 다음 터미널의 아이콘 문자열을 다음으로 설정합니다.^Umy command
그런 다음 터미널은 해당 이름을 입력 대기열에 삽입하고 마지막으로 저장된 값으로 재설정하라는 요청을 받습니다. 올바른 구성으로 실행되는 대화형 셸 bash
에서는 보이지 않아야 하지만 이는 아마도 나쁜 생각일 것입니다. xterm
아래 Stéphane의 의견을 참조하세요.
printf
그래도 내 컴퓨터에서 다른 이스케이프 시퀀스를 사용하여 비트를 실행한 후 터미널이라는 용어에 대한 사진이 있습니다. printf
내가 입력하는 명령의 모든 개행 문자 에 대해CTRL+V
그 다음에CTRL+J
그런 다음 누르세요ENTER
열쇠. 그 이후에는 아무것도 입력하지 않았는데, 보시다시피 터미널이 주입되었습니다.my command
라인 분야의 입력 대기열을 입력하십시오.
이를 수행하는 실제 방법은 중첩된 pty를 사용하는 것입니다. 이것이 작동 방식 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
이것은 결코 이식성이 없지만 적절한 개방 권한이 있는 대부분의 Linux 시스템에서 작동합니다 /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
...GNU 시스템에서 실행하는 경우(또는 stdin에서도 읽을 수 있는 표준 C를 사용하는 다른 컴파일러)pts
는 표준 입력에서 함수를 실행 unlockpt()
하고 방금 잠금 해제된 pty 장치의 이름을 표준 출력에 쓰는 작은 실행 가능 바이너리를 작성합니다 . 퇴근하면서 쓴건데..이 pty를 어떻게 구하고 어떻게 할 수 있나요?.
어쨌든, 위의 모든 코드는 bash
현재 tty 아래의 pty 계층에서 쉘을 실행합니다. bash
모든 출력을 슬레이브 pty에 쓰라는 지시를 받았으며 현재 tty는 -echo
입력을 구성하거나 버퍼링하지 않고 대신 전달하도록 구성되었습니다.(최대) raw
에 cat
복사 bash
하는 동시에 다른 백그라운드 cat
는 모든 슬레이브 출력을 현재 tty에 복사합니다.
대부분의 경우 위 구성은 전혀 쓸모가 없습니다. 기본적으로 중복될 뿐입니다.와는 별개로우리는 bash
pty master fd의 자체 사본을 에 게시합니다 <>9
. 이는 bash
간단한 리디렉션을 통해 자신의 입력 스트림에 자유롭게 쓸 수 있음을 의미합니다. bash
당신이 해야 할 일은 :
echo echo hey >&9
...혼자서 얘기하는 중이군요.
여기 또 다른 사진이 있습니다:
답변4
맙소사 우리가 놓쳤어Bash에 내장된 간단한 솔루션: 이 명령에는 와 함께 사용할 때 텍스트를 입력 버퍼에 푸시하는 read
옵션이 있습니다 . 매뉴얼 페이지에서:-i ...
-e
-나 텍스트
readline을 사용하여 행을 읽으면 편집이 시작되기 전에 텍스트가 편집 버퍼에 배치됩니다.
따라서 사용자에게 명령을 제공하고 응답을 실행하거나 평가하는 작은 bash 함수 또는 쉘 스크립트를 작성하십시오.
domycmd(){ read -e -i "$*"; eval "$REPLY"; }
의심할 바 없이 이것은 32년 넘게 존재해 온 ioctl(,TIOCSTI)을 사용합니다.2.9BSD ioctl.h.