Возможно вы искали: 'Burn It All: Journey t...'

May 15 2025 18:51:45
  • Как сделать 8Gamers.Ru домашней страницей?
  • Игры
    • База данных по играх
    • Игровые новости
    • Игровая индустрия
    • Обзоры на игры
    • Прохождения игр
    • Гайды к играм
    • Превью о играх
    • Игровые тизеры
    • Игровые арты
    • Игровые обои
    • Игровые скриншоты
    • Игровые обложки
    • Игровые трейлеры
    • Игровое видео
    • Вышедшие игры
    • Ближайшие релизы игр
  • Кино и ТВ
    • База данных по кино
    • Статьи о кино
    • Постеры
    • Кадры из кино
    • Кино трейлеры
    • Сегодня в кино
    • Скоро в кино
  • Комиксы и манга
    • Манга по алфавиту
    • База данных по комиксах
    • Читать онлайн комиксы
    • Читать онлайн манга
    • База персонажей
  • Читы и коды
    • Чит-коды для PC игр
    • Чит-коды для консольных игр
    • Трейнеры
    • Коды Game Genie
  • Моддинг
    • Модификации
    • Карты к играм
    • Программы для моддинга
    • Статьи о моддинге
  • Геймдев
    • Всё о создании игр
    • Список движков
    • Утилиты в помощь игроделу
    • Конструкторы игр
    • Игровые движки
    • Библиотеки разработки
    • 3D-модели
    • Спрайты и тайлы
    • Музыка и звуки
    • Текстуры и фоны
  • Рецензии
    • Игры
    • Кино
    • Аниме
    • Комиксы
    • Мангу
    • Саундтреки
  • Саундтреки
    • Лирика
  • Файлы
    • Патчи к играм
    • Русификаторы к играм
    • Сохранения к играм
    • Субтитры к кино
  • Медиа
    • Видео
    • Фото
    • Аудио
    • Фан-арты
    • Косплей
    • Фото с виставок
    • Девушки из игр
    • Рисунки
    • Рисуем онлайн
    • Фотохостинг
  • Юмор
    • Анекдоты
    • Афоризмы
    • Истории
    • Стишки и эпиграммы
    • Тосты
    • Цитаты
  • Флеш
    • Азартные
    • Аркады
    • Бродилки
    • Гонки
    • Для девочек
    • Для мальчиков
    • Драки
    • Квесты
    • Леталки
    • Логические
    • Мультфильмы
    • Открытки
    • Приколы
    • Разное
    • Спорт
    • Стратегии
    • Стрелялки
Статистика

Статей: 87772
Просмотров: 96111483
Игры
Injustice:  Gods Among Us
Injustice: Gods Among Us
...
Dark Souls 2
Dark Souls 2
Dark Souls II - вторая часть самой хардкорной ролевой игры 2011-2012 года, с новым героем, сюжето...
Battlefield 4
Battlefield 4
Battlefield 4 - продолжение венценосного мультиплеер-ориентированного шутера от первого ли...
Кино
Steins;Gate
Steins;Gate
Любители японской анимации уже давно поняли ,что аниме сериалы могут дать порой гораздо больше пи...
Ку! Кин-дза-дза
Ку! Кин-дза-дза
Начинающий диджей Толик и всемирно известный виолончелист Владимир Чижов встречают на шумной моск...
Обзоры на игры
• Обзор Ibara [PCB/PS2] 18357
• Обзор The Walking ... 18801
• Обзор DMC: Devil M... 19879
• Обзор на игру Valk... 15877
• Обзор на игру Stars! 17764
• Обзор на Far Cry 3 17948
• Обзор на Resident ... 16024
• Обзор на Chivalry:... 17508
• Обзор на игру Kerb... 17981
• Обзор игры 007: Fr... 16619
Превью о играх
• Превью к игре Comp... 17960
• Превью о игре Mage... 14464
• Превью Incredible ... 14721
• Превью Firefall 13479
• Превью Dead Space 3 16334
• Превью о игре SimC... 14730
• Превью к игре Fuse 15442
• Превью Red Orche... 15542
• Превью Gothic 3 16343
• Превью Black & W... 17354
Главная » Статьи » Разное » Интерактивные программы в скриптах UNIX (shell expect perl tcl python)

Интерактивные программы в скриптах UNIX (shell expect perl tcl python)

Ключевые слова: shell, expect, perl, tcl, python, (найти похожие документы)

From: Mikhail E. Zakharov <zakharov@ipb.redline.ru.>
Newsgroups: email
Date: Mon, 17 May 2005 14:31:37 +0000 (UTC)
Subject: Интерактивные программы в скриптах UNIX


Как ни крути,
но рано или поздно становится понятно, что shell-скрипты для
администрирования UNIX писать все же придется. В том числе и те,
которые будут взаимодействовать с интерактивными программами такими,
как telnet, ftp, su, passwd, ssh. Но тогда можно быть уверенным, что
спокойной жизни администратора наступил конец, поскольку
интерактивность программ таит в себе множество подводных камней,
которые не встречаются в программировании рядовых shell-скриптов. Хотя
к счастью, или нет, большинство этих проблем традиционно проявляются в
течение первых пяти минут и выглядят для автора скрита как
невозможность пройти аутентификацию на сервере. И поначалу это
обстоятельство ставит в тупик, поскольку привычные конвейерные
конструкции вида:

$ echo luser && echo TopSecret | telnet foo.bar.com


вроде бы срабатывать отказываются и в результате простая, на первый
взгляд, проблема приобретает статус невыполнимого задания. Однако, не
все потеряно, и если не вдаваться в суть проблемы, хотя мы это чуть
позже обязательно сделаем, простое решение появится довольно быстро,
ведь многие из диалоговых программ имеют встроенные механизмы
обработки скриптов, как например, стандартный ftp-клиент FreeBSD:

$ echo '$FILEPUT' | ftp -N ftprc luser@foo.bar.com


Эта команда заставит ftp подключиться к хосту foo.bar.com под именем
пользователя luser и выполнить макрос FILEPUT (закачка файла на
сервер) описанный в файле ftprc. В этом же файле кроме макроса, должны
быть обязательно описаны хост, логин и пароль пользователя на этом
хосте:

$ cat ftprc
machine foo.bar.com
login luser
password TopSecret

macdef FILEPUT
binary
cd /tmp
put some_usefull_file.bin
bye
<-- Внимание! Здесь обязательный перевод строки в конце макроса.
$


Если же диалоговая программа по какой-то причине не поддерживает
встроенные скрипты, то среди свободно-распространяемого ПО всегда
найдется ее аналог, в котором уже давно реализована возможность
выполнять действия автоматически. В самом деле, вы же не первый
столкнулись с подобной задачей!

Другой способ заставить диалоговую программу выполнить что-либо без
участия пользователя, это перенаправить ее стандартный ввод. Например,
так в сильно упрощенном виде выглядит скрипт загрузки Oracle:

#!/bin/sh

su - oracle -с /oracle/bin/svrmgrl <<EOF
connect internal
startup
EOF


Однако этот способ не помощник при работе с программами типа telnet
поскольку он не защищен от пресловутой "проблемы аутентификации
пользователя". Ситуация к тому же осложняется трудностями отладки
скриптов в момент этой самой аутентификации. И понятно, что для
разрешения таких ситуаций требуется какое-то специальное решение,
поиск которого, естественно, традиционно осуществляется в интернете.
Беглое штудирование поисковых систем на предмет проблемы принесет
плоды в виде невнятных бормотаний по поводу, преждевременного закрытия
входного потока данных, псевдо-терминалов (pty) и прочее, но среди
всего этого бестолкового обилия обязательно будут присутствовать
ссылки и на expect.


expect

это как раз именно то, что и требовалось найти: утилита, которую
традиционно используют для автоматизации работы с интерактивными
программами. И как это обычно бывает, к сожалению имеется и одно
маленькое неудобство: для работы expect необходим еще один
установленный в системе язык программирования - TCL. Правда если
инсталляция и изучение еще одного, правда очень могучего, языка вас не
смущает, то на этом свои поиски можно прекращать: для написания
скриптов expect и TCL/TK имеют все необходимое и даже больше.

Если в вашей системе expect отсутствует, то его следует
инсталлировать. Во FreeBSD это удобно сделать используя систему
портов:

# cd /usr/ports/lang/expect
# make install clean


В результате expect и все что ему необходимо буде скачано из интернет
и установлено в системе.

Теперь с TCL и expect можно работать и применительно к нашей проблеме
"интерактивности" expect-скрипт описывающий короткую telnet-сессию с
FreeBSD на хост foo.bar.com (пусть это будет SCO UnixWare-7.1.3) под
именем пользователя luser с паролем TopSecret может выглядеть примерно
так:

#!/usr/bin/expect

spawn telnet foo.bar.com
expect ogin {send luserr}
expect assword {send TopSecretr}
send "who am ir"
send "exitr"
expect eof


В принципе, в README к expect сказано, что существует библиотека
libexpect, которую можно использовать при написании программ на C/C++
избежав при этом использования самого TCL. Но скорее всего, эта тема
не вписывается в рамки данной статьи, да и сами авторы expect
склоняются к мысли, что проще использовать скрипты expect, а не
библиотеку.

Однако, если несмотря на всю привлекательность вышеизложенного метода
и уговоры авторов из FAQ по expect, вы решили не использовать expect,
значит вы либо слишком ленивы, либо ваша душа уже насквозь отравлена
языком Perl. Чтож, в этом случае ваше спасение в установке
соответствующего модуля Perl
(http://sourceforge.net/projects/expectperl), который призван
обеспечить функционал оригинального expect'а. Под FreeBSD это можно
осуществить знакомым методом установки из портов:

# cd /usr/ports/lang/p5-Expect
# make install clean


Теперь наш пример с telnet-сессией будет выглядеть так:

#!/usr/bin/perl

use Expect;

my $exp = Expect->spawn("telnet foo.bar.com");
$exp->expect($timeout,
[ 'ogin: $' => sub {
$exp->send("lusern");
exp_continue; }
],

[ 'assword:$' => sub {
$exp->send("TopSecretn");
exp_continue; }
],
'-re', qr'[#>:] $'
);
$exp->send("who am in");
$exp->send("exitn");
$exp->soft_close();


Если же я ошибся, в вашей приверженности языку Perl, у вас всегда есть
возможность использовать Python для которого написан соответствующий
модуль pexpect (http://pexpect.sourceforge.net). Язык Python,
естественно, уже должен быть проинсталлирован в системе заранее. Если
нет, порты FreeBSD нас снова выручат:

# cd /usr/ports/lang/python
# make install clean


И, соответственно, для модуля pexpect:

# cd /usr/ports/misc/py-pexpect
# make install clean


Скрипт telnet-сессии на Python будет таким:

#!/usr/local/bin/python

import pexpect

child = pexpect.spawn('telnet foo.bar.com');

child.expect('ogin: ');
child.sendline('luser');

child.expect('assword:');
child.sendline('TopSecret');

child.sendline('who am i');
child.sendline('exit');

child.expect(pexpect.EOF);

print child.before;


Конечно, если и Python вас по какой-то причине не устраивает, тогда вы
можете установить, например, PHP. Ну, в общем, вы поняли, поиск
удобных вариантов решений продолжать можно довольно долго, и разве что
только Visual Basic'а в этом списке не будет. Поэтому думаю, настало
время, интересное это занятие отложить в сторону, и наконец,
попытаться понять скрытую суть вещей.


Суть вещей

Итак, при запуске интерактивной программы из shell-скрипта на самом
деле происходит следующее... И хотя эта фраза звучит в стиле
заключительной речи сыщика Пуаро, до конца повествования на самом деле
еще довольно далеко и имеет смыс начать издалека, т.е. с самого
начала. А потому, просто необходимо забыть все те красивости, которые
предлагаются expect'ом или его, в высшей степени, достойными клонами.

Для начала попытаемся с имитировать некое грубое подобие expect-like
программы при помощи скриптов shell с использованием всего арсенала
стандартных утилит *NIX-системы и попытаемся таки хоть отчасти уловить
то самое, что указано в заголовке раздела. Важно, также отметить, что
все эксперименты справедливы для FreeBSD и нет никаких гарантий, что
они дадут те же результаты и на других операционных системах.

Чтобы максимально упростить нашу задачу, и не бороться с конвейерами,
упомянутыми в первых примерах в самом начале статьи, создадим два
fifo-файла, один для стандартного ввода (in.fifo), другой для вывода
(out.fifo), и бог с ним пока со стандартным потоком ошибок:

$ mkfifo in.fifo
$ mkfifo out.fifo


Далее, запустим неудачный в плане безопасности, и, из-за примеров на
expect, perl и python, досмерти надоевший telnet с перенаправлениями
потоков ввода-вывода на in.fifo и out.fifo:

$ telnet -K localhost > out.fifo < in.fifo


Маленький шаг в сторону: поскольку все эксперименты проводятся на
FreeBSD, то при попытке подключения к telnet-серверу, тоже
загруженному на FreeBSD, автоматически включаются механизмы (SRA),
призванные обеспечить безопасность telnet-сессии:

$ telnet localhost
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Trying SRA secure login:
User (luser): <-- ожидание ввода логина (строка не переведена)


Чтобы отключить такое поведение и вернуть telnet'у традиционный вид,
будем загружать telnet с ключем -K:

$ telnet -K localhost
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

FreeBSD/i386 (unity) (ttyp1)

login: <-- ожидание ввода логина (строка не переведена)


Итак, пусть наш первый скрипт test_1.sh пока состоит из следующих
строк:

#!/bin/sh

mkfifo in.fifo
mkfifo out.fifo

telnet -K localhost > out.fifo < in.fifo


Теперь запустив скрипт на исполнение:

$ ./test_1.sh &


можно начинать проводить эксперименты. Обратите внимание на параметр
&, переводящий скрипт в фоновое выполнение команды, это сделано для
того, чтобы иметь возможность продолжать работу с тем же терминалом во
время наших опытов. Например, попробуем прочитать что-либо из out.fifo
и написать что-либо в in.fifo.

$ cat out.fifo &


Параметр здесь & указан по той же самой причине, что и в случае с
вызовом скрипта. Правда в результате выполнения команды cat на экране,
к сожалению, ничего не появится. Видимо, это происходит из-за
блокировок чтения/записи при работе fifo-файлов: запись в fifo-файл
блокируется пока из него никто не читает, и чтение из fifo-файла тоже
блокируется, пока другая сторона не готова в него писать. Вероятно,
весь процесс тормозит наш in.fifo, в который ничего не записано.
Проверим эту догадку послав перевод строки в input-канал:

$ echo > in.fifo


Была ли догадка правильной, или истинная причина скрывается в чем-то
другом, но чудо таки произошло! На терминале появились долгожданные
результаты работы команды cat out.fifo:

$ Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

FreeBSD/i386 (unity) (ttyp1)

login: login:


Единственное, что смущает, так это дважды повторяющиеся login:. На
самом деле, это естественная реакция telnet-сервера на то, что выше
командой: echo > in.fifo ему был послан перевод строки.

Сделав необходимый вывод, чтобы избежать отсылки перевода строки,
заменим команду echo > in.fifo на:

$ echo -n > in.fifo


А еще лучше, будет использовать комбинацию:

$ cat > in.fifo &


Это должно в будущем предотвращать закрытие канала ввода, что
справедливо воспринимается telnet'ом, как разрыв связи.

Чтож, теперь можно продолжать наши изыскания, но для начала следует
избавиться от background-процессов, которые появились в результате
использования &:

$ fg
./test_1.sh
^C[2] + Done cat out.fifo


Команда fg и затем нажатие ^C на клавиатуре для того, чтобы прервать
работу процесса.

Итак, следующим шагом будет попытка отфильтровать выходной поток
(out.fifo), чтобы исходя из заданного шаблона "отловить" необходимые
данные чтобы реализовать основную комбинацию команд expect:

expect request {send answer}


Сама собой напрашивается какая-нибудь такая связка:

$ cat out.fifo | grep request && echo answer


Однако, в нашем случае цепочка не будет правильно срабатывать уже на
этапе grep. Это объясняется тем, что grep предназначен для распечатки
строк, соответствующих указанному шаблону, и поэтому совершенно
естественно, что перед началом сравнения данного шаблона с каждой
новой строкой, grep всегда ожидает окончания ввода этой строки (n)
или же окончания файла (). В нашем случае эта особенность делает
невозможным перехват login: при помощи grep поскольку за login: не
следует перевод строки (система ожидает от пользователя ввод логина),
этот момент выше отражен на примере telnet -K localost. Таким образом
grep будет вечно (до истечения таймаута у telnet-сервера) ожидать
получения конца строки, а затем увидит сразу конец файла.

Необходим другой механизм обработки таких незаконченных строк. Как
вариант, возможно вместо cat использовать команду dd, которая в цикле
будет посимвольно передавать данные grep'у. Я имею ввиду следующую
конструкцию, которая показана на примере уже работающего скрипта
expect.sh:

#!/bin/sh

while :; do
dd if=out.fifo bs=1b count=1 2>/dev/null | grep $1
if [ $? -eq 0 ]; then
# Match found
echo "$2" > in.fifo
exit 0
fi
# Match not found, let's play again
done


Запускать скрипт можно следующим образом (файлы in.fifo и out.fifo уже
должны быть созданы):

$ ./expect.sh "request" "answer"


Чтож, настало время собрать воедино в одном скрипте (test_2.sh) весь
полученный опыт и попытаться автоматизировать нашу традиционную
telnet-сессию:

#!/bin/sh

mkfifo out.fifo in.fifo

telnet -K localhost 1> out.fifo 0< in.fifo &

cat > in.fifo &
cat out.fifo > out.fifo &
pid=`jobid`

./expect.sh "ogin" "zmey"
./expect.sh "word" "SaracSh"

sleep 1
echo 'who am i > /tmp/test.txt' > in.fifo
sleep 1
echo "exit" > in.fifo

rm out.fifo in.fifo
kill $pid


Запустив этот скрипт на выполнение, если все удачно, получится
следующий незамысловатый вывод:

$ ./test_2.sh
login:
Password:
Connection closed by foreign host.


Зато в качестве боевого трофея останется файл /tmp/test.txt, который
будет подтверждать успешность эксперимента:

$ cat /tmp/test.txt
luser ttyp3 May 10 16:39 (localhost)


Если же что-то пошло неудачно, вероятно придется воспользоваться
командой kill для каждого процесса, оставшегося от провалившегося
опыта.

К сожалению, скрипт этот работает крайне нестабильно: он сильно
зависит от величин параметра sleep и скорости ответа telnet-сервера
из-за чего не всегда данные приходят вовремя, что ведет к зависаниям и
процессы приходится часто убивать. Ясно также, что такая конструкция
работает не везде, например в Linux мне не удалось добиться хоть
сколько-нибудь приемлемых результатов, но если это интересно, путь
любители Linux'а этим и занимаются.


Надо идти дальше

и найти утилиту, решил я, которую можно было бы без всяких надстроек
типа TCL, Perl, Python использовать в качестве expect-заменителя для
чистого shell. Ясно, что написана она должна быть на С и быть
портирована под возможно большее количество операционных систем. Чтож,
let's Google! И через некоторое время такая программа нашлась, это
оказалась pty-4.0 написанная Daniel J. Bernstein в 1992 году. Однако,
после этого релиза, программа, судя по всему, больше не развивалась.

Через некоторое время исходный код pty-4.0 у меня даже собрался в
бинарный, и некоторые части pty-4.0 стали запускаться. Но к этому
моменту стало очевидно, что проще написать свою программу, чем
разбираться со старой.

А почему бы и не написать? И я углубился в более серьезное изучение
вопроса. Довольно быстро я узнал, что, действительно, наиболее удобный
способ взаимодействия с интерактивными программами, это именно
имитация для них терминала. И место псевдо-терминалов в структуре
будущей программы четко определилось несмотря даже на сбивчивые
бубнения специалистов из интернета насчет expet'а и pty-сессий. Стало
также понятно, что метод запуска приложений под контролем pty-сессий
очень удобно выполнять внутри какой-либо оболочки, например, TCL, Perl
и пр. Однако для тех же целей, ничего не мешает использовать программу
на С и чистый интерпретатор sh.

В результате всего этого, уже через пару недель у меня была готова
рабочая версия empty (http://www.sourceforge.net/projects/empty),
которая позволяет запускать интерактивные программы и вести с ними
диалог посредством fifo-файлов. Например, надоевшая FreeBSD сессия
telnet в варианте shell-скрипта для empty будет выглядеть так:

#!/bin/sh

empty -f -i in.fifo -o out.fifo telnet -K localhost
empty -w -i out.fifo -o in.fifo -t 5 "ogin:" "luser"
empty -w -i out.fifo -o in.fifo -t 5 "assword:" "TopSecret"
empty -s -o in.fifo 'who am i > /tmp/test.txt'
empty -s -o in.fifo 'exit'


Чтож, это гораздо короче, чем кривоватый скрипт test_2.sh, да и
работает утилита вполне устойчиво на *BSD, Linux и Solaris не требуя
при этом наличия TCL, Perl или Python. Правда, функций в программе
пока меньше, чем у ее взрослых аналогов, но возможно, все еще впереди.
1322 Прочтений •  [Интерактивные программы в скриптах UNIX (shell expect perl tcl python)] [08.05.2012] [Комментариев: 0]
Добавил: Ukraine Vova
Ссылки
HTML: 
[BB Url]: 
Похожие статьи
Название Добавил Добавлено
• Интерактивные программы в скриптах ... Ukraine Vova 08.05.2012
Ни одного комментария? Будешь первым :).
Пожалуйста, авторизуйтесь для добавления комментария.

Проект входит в сеть сайтов «8Gamers Network»

Все права сохранены. 8Gamers.NET © 2011 - 2025

Статьи
Рецензия на Pressure
Рецензия на Pressure
Чтобы обратить на себя внимание, начинающие маленькие разработчики, как правило, уходят в жанры, ...
Рецензия на Lost Chronicles of Zerzura
Рецензия на Lost Chron...
Игры, сделанные без любви и старания, похожи на воздушный шар – оболочка есть, а внутри пусто. Lo...
Рецензия на The Bridge
Рецензия на The Bridge
«Верх» и «низ» в The Bridge — понятия относительные. Прогуливаясь под аркой, можно запросто перей...
Рецензия на SimCity
Рецензия на SimCity
Когда месяц назад состоялся релиз SimCity, по Сети прокатилось цунами народного гнева – глупые ош...
Рецензия на Strategy & Tactics: World War 2
Рецензия на Strategy &...
Название Strategy & Tactics: World War II вряд ли кому-то знакомо. Зато одного взгляда на ее скри...
Рецензия на игру Scribblenauts Unlimited
Рецензия на игру Scrib...
По сложившейся традиции в информационной карточке игры мы приводим в пример несколько похожих игр...
Рецензия на игру Walking Dead: Survival Instinct, The
Рецензия на игру Walki...
Зомби и продукция-по-лицензии — которые и сами по себе не лучшие представители игровой биосферы —...
Обратная связь | RSS | Донейт | Статистика | Команда | Техническая поддержка