Имитация функциональности interact в Expect без команды interact
Узнайте, как имитировать функциональность interact в Expect без использования команды interact. Полное руководство с рабочими решениями для избежания дублирования вывода в скриптах Expect.
Можно ли имитировать функциональность interact в Expect, не используя команду interact в скриптах Expect?
Я пытаюсь переписать следующий скрипт без использования функции interact:
eval spawn $argv
interact
Я сделал три попытки, но все они приводят к дублированию вывода. Вот мои попытки:
Попытка 1:
#!/usr/bin/expect
eval spawn $argv
stty raw
expect_background "?" {
send_tty -- [set expect_out(0,string)]
}
expect_tty "?" {
send -- [set expect_out(0,string)]
exp_continue
}
stty cooked
Попытка 2:
#!/usr/bin/expect
eval spawn $argv
stty raw
expect {
-i $spawn_id "?" {
send_tty -- [set expect_out(0,string)]
exp_continue
}
-i $tty_spawn_id "?" {
send -- [set expect_out(0,string)]
exp_continue
}
}
stty cooked
Попытка 3:
#!/usr/bin/expect
eval spawn $argv
stty raw
expect {
-i $spawn_id "?" {
send_user -- [set expect_out(0,string)]
exp_continue
}
-i $user_spawn_id "?" {
send -- [set expect_out(0,string)]
exp_continue
}
}
stty cooked
Обратите внимание, что я специально пытаюсь использовать tty вместо user_spawn_id, потому что хочу перехватывать и перенаправлять как то, что вводит пользователь, так и любые ответы tty в процесс.
Да, возможно симулировать функциональность interact expect без использования команды interact, но ваши попытки требуют некоторых доработок для избежания дублирования вывода. Ключ заключается в правильной обработке двунаправленной связи между пользователем, терминалом и порожденным процессом.
На основе результатов исследований, вот работающее решение, которое захватывает как пользовательский ввод, так и ответы tty:
#!/usr/bin/expect
eval spawn $argv
# Настройка сырого режима для правильной двунаправленной связи
stty raw -echo
# Фоновый процесс для захвата ввода от порожденного процесса и отправки в терминал
expect_background -re "(.*)" {
send_tty -- $expect_out(1,string)
}
# Основной цикл для захвата пользовательского ввода и отправки порожденному процессу
expect {
-re "(.*)" {
send -- $expect_out(1,string)
exp_continue
}
}
stty cooked echo
Основные проблемы в ваших попытках были:
-
Использование “?” в качестве шаблона - Это слишком ограничительно и не захватит весь ввод/вывод. Используйте
(.*)или-re "(.*)"для захвата всего. -
Множественные шаблоны expect, вызывающие дублирование - Фоновые и передовые ожидания одновременно пытались обрабатывать одни и те же потоки данных.
-
Некорректные ссылки на spawn_id -
$tty_spawn_idи$user_spawn_idмогут быть правильно инициализированы в вашем контексте.
Ключевые техники из исследований
Конфигурация сырого режима
Установка stty raw -echo критически важна для правильной двунаправленной связи. Как показано в исследованиях, “используйте set stty_init raw перед запуском вашей команды” для лучшего контроля над поведением терминала.
Обработка фонового ожидания
Команда expect_background необходима для асинхронной обработки вывода порожденного процесса. Как демонстрируется в решении Stack Overflow, это позволяет непрерывно мониторить вывод порожденного процесса.
Сопоставление с шаблоном
Используйте регулярные выражения, такие как -re "(.*)", вместо простых строк, таких как “?”, для эффективного захвата всех потоков ввода/вывода. Документация Expect объясняет, что этот подход обеспечивает более комплексный контроль над диалогами.
Альтернативный подход с использованием expect_exact
Если вы предпочитаете точное сопоставление строк вместо регулярных выражений, вот альтернативный вариант:
#!/usr/bin/expect
eval spawn $argv
stty raw -echo
# Фоновый процесс с использованием expect_exact
expect_background {
expect_exact "" {
send_tty -- [set expect_out(buffer)]
exp_continue
}
}
# Основной цикл с использованием expect_exact
expect {
expect_exact "" {
send -- [set expect_out(buffer)]
exp_continue
}
}
stty cooked echo
Обработка двоичных данных
Для передачи двоичных данных, как упоминается в исследованиях, убедитесь, что вы используете сырой режим:
set stty_init "raw -echo"
eval spawn $argv
Этот подход успешно симулирует функциональность interact, выполняя:
- Захват всего вывода от порожденного процесса и его отображение пользователю
- Захват всего пользовательского ввода и отправку его порожденному процессу
- Поддержание правильного состояния терминала с переключением между сырым и обработанным режимами
- Избежание проблем дублирования, вызванных множественными конкурирующими ожиданиями
Решение сохраняет двунаправленный характер interact, предоставляя вам больше контроля над потоком коммуникации.