возможно, вам просто нужно сделать:
stty sane
Я заметил, что на странице forkpty()
man
сказано, что он скопирует настройки termios из *termp
на вновь открытый pty, но не сказано, что он делает с ними в противном случае, и единственный не-NULL аргумент, который вы передаете forkpty()
- для главного fd pty. Я бы предположил, что в итоге вы получите полностью NULL-структуру termios, что не может быть очень полезным. Это не будет беспокоить bash
, который имеет readline()
для обработки всех своих собственных терминальных вещей, и поэтому он будет интерпретировать все символы по умолчанию, так или иначе.
вот цитата из довольно информативной статьи на эту тему:
опция
может быть полезна для подглядывания за тем, что другая программа делает с терминалом. Если вы запустите-F
программы sttytty
в оболочке, она выведет путь к терминальному устройству этой оболочки (обычно в виде/dev/pts/N
, по крайней мере, в Linux). Теперь, из другой оболочки, вы можете запуститьstty -a -F /dev/pts/N
, чтобы увидеть, как настроен терминал первой оболочки. Затем можно запустить программы в первой оболочке и повторить командуstty
во второй оболочке, чтобы увидеть, какие настройки установлены. Например, если я запущуstty -F /dev/pts/10
прямо сейчас (в то время как у меняbash
разговаривает сgnome-terminal
через этот pty), я увижу:
$ stty -F /dev/pts/10
speed 38400 baud; line = 0;
eol = M-^?; eol2 = M-^?; swtch = M-^?; lnext = ; min = 1; time = 0;
-icrnl iutf8
-icanon -echo
Итак, мы видим, что
bash/readline
отключилCR→LF
перевод на входе (icrnl
), отключилcanonical
режим иecho
, но включил режим UTF-8 (потому чтоbash
обнаружил локаль utf-8). Обратите внимание, что если я запускаюstty
непосредственно в этой оболочке, я вижу нечто несколько иное:
$ stty
speed 38400 baud; line = 0;
eol = M-^?; eol2 = M-^?; swtch = M-^?;
iutf8
Это происходит потому, что
bash
поддерживает свой собственный наборtermios
настроек (дляreadline
), и сохраняет и восстанавливает настройки во время работы программ, так что настройки, установленные во время работы программы, отличаются от настроек, установленных во время ввода текста в приглашенииbash
.
%./mystery
a
b
c
%
Можно подать сигнал STOP
программе, а затем CONT
продолжить ее выполнение; следующий код TCL ожидает появления b
на выходе и в этот момент останавливает процесс, который должен оставаться остановленным до тех пор, пока пользователь не введет строку для expect_user
, чтобы воздействовать на (как минимум на новую строку ).
#!/usr/bin/env expect
spawn -noecho./mystery
set spid [exp_pid]
expect -ex b { exec kill -STOP $spid; send_user "STOP\n" }
expect_user -re. { exec kill -CONT $spid }
expect eof
Это, конечно, имеет всевозможные проблемы, например, если mystery
работает слишком быстро, или если вывод буферизуется и т. д. Мне пришлось замедлить C и отключить буферизацию, чтобы это сработало:
% cat mystery.c
#include <stdio.h>
#include <unistd.h>
int main(void)
{
setvbuf(stdout, (char *) NULL, _IONBF, (size_t) 0);
printf("a\n");
sleep(1);
printf("b\n");
sleep(1);
printf("c\n");
return 0;
}
Программой на C можно лучше управлять, запуская ее под отладчиком, таким как gdb
;точки останова были бы гораздо более точным способом остановить выполнение в определенной точке кода, чем реагировать на ввод-вывод. Символы отладки помогут, но не обязательны:
% gdb mystery
Reading symbols from mystery...(no debugging symbols found)...done.
(gdb) quit
% otool -dtv mystery | grep callq
0000000100000f26 callq 0x100000f70
0000000100000f32 callq 0x100000f6a
0000000100000f3c callq 0x100000f76
0000000100000f48 callq 0x100000f6a
0000000100000f52 callq 0x100000f76
0000000100000f5e callq 0x100000f6a
Так что на самом деле это на Mac (разборка зависит от платформы ). Выше приведены вызовы setvbuf
, printf
и sleep
, поэтому с начальным адресом
% otool -dtv mystery | sed 3q
mystery:
_main:
0000000100000f06 pushq %rbp
% perl -E 'say 0x0000000100000f52 - 0x0000000100000f06'
76
% gdb mystery
Reading symbols from mystery...(no debugging symbols found)...done.
(gdb) b *main + 76
Breakpoint 1 at 0x100000f52
(gdb) r
Starting program: /Users/jhqdoe/tmp/mystery
a
b
Breakpoint 1, 0x0000000100000f52 in main ()
(gdb)
И тогда вы можете делать все, что необходимо, и продолжать программу по своему усмотрению.
Другой идеей было бы использовать LD_PRELOAD
для настройки поведения программы, предполагая, конечно, что наиболее разумный вариант — перекомпилировать программу из исходного кода — невозможен. Еще одним вариантом было бы исправить двоичный файл C, чтобы он вел себя как нужно .
Вы можете использовать read
, который ожидает ввода пользователем, прежде чем продолжить
Пример:
Эта программа запускает цикл и выводит вывод ls -lhtr
, ожидает ввода пользователя (Нажмите клавишу ввода или любой другой символ ), а затем снова выводит вывод и продолжает процесс в бесконечном цикле
#!/bin/bash
while (true); do
ls -lhtr;
read i;
done
Таким образом, в основном вместо ls -lhtr
вы можете использовать команду, выходные данные которой вам нужно отслеживать, после того, как вы закончите изменение среды и файлов, вы можете нажать любую клавишу, чтобы снова продолжить мониторинг вывода команды