В очередной раз используя этот скрипт в одном из учебных классов, я поискал материалы и обнаружил, что здесь давно не вспоминали об expect. Это замечательный альтернативный интерпретатор для командной строки Linux, который может общаться с ней вместо живого человека, и я добавлю сюда лишь ещё один пример его применения.
Картинок на эту тему особо нет, а в статье и вообще не будет, поэтому привлечём ваше внимание обложкой замечательной книги
Немного истории и оффтопика
В начале 2013го я вернулся в дополнительное образование детей, получил 24 часа еженедельной нагрузки для четырёх групп «юных программистов» и «юных системных администраторов», и приступил к набору учеников на двух площадках: моём собственном кабинете и кабинете информатики находящейся неподалёку гимназии. Силами групп «юных системных администраторов» мы привели свой кабинет в порядок, развернув AltLinux 6 и парочку альтернативных дистрибутивов. А в гимназии очень опытный «инженер компьтерного класса» давно вёл эксперименты с source-based, закончившиеся приходом Calculate Linux на все машины учителей и учебных классов. Респект ему)
Задача
Через пару месяцев занятий я увидел проблему. Дети отказывались уходить с занятий, любым способом стараясь задержаться подольше. Т.к. педагогические технологии — это не моё, а кружок у нас всё-таки технический, я убивал сторонние процессы и выключал машины по ssh. Это повысило интерес учеников к изучению возможностей командной строки. Однако скоро они нашли баг: выключение «руками» занимает слишком много времени, и даже в небольшом кабинете они успеют перезапустить половину машин до того, как я завершу карательный процесс, и это затянет дело. Чтобы продемонстрировать кто здесь главный лучшие возможности программирования для командной строки, я задумался об автоматизации.
Варианты решения
Нулевой мыслью было использование italc, и мы даже уделили несколько недель его настройке и экспериментам. Но он оказался слишком глючен и примитивен, поэтому был благополучно забыт.
Первой же мыслью было настроить доступ через ssh по отпечатку. Это сократило бы задачу до одного цикла, но для применения «на коленке» этот способ оказался не совсем пригоден (хотя почему нет? ЕМНИП, отпечаток для пользователя также можно создать без рута). Но при доступной авторизации по паролю (кстати, большой ущерб безопасности для учебных классов, где логин-пароли одинаковы) меня заинтересовал вариант с автоматической авторизацией по паролю. Уделив час поиску, я нашёл несколько примеров для expect.
Решение через expect
Перед началом
Но, во первых, он должен быть установлен. В моём классе мы без труда сделали это, а вот в классе гимназии ВНЕЗАПНО оказалось, что и expect, и nmap, и некоторые другие интересные системные утилиты не только установлены, но и доступны ученику. Это очень помогло нам, когда в очередной раз «упал» прикрученный по NFS сетевой диск, и мы нашли способ распространения заданий через быстро найденный бухгалтерский компьютер с расшаренными дисками.
Во вторых, кроме самого expect, нам понадобится использовать 2 типа цикла: с предусловием и с параметром. Первый необходим для «зацикливания» процесса, чтобы можно было повесить выполнение скрипта фоном на всё занятие. Второй же необходим для перебора необходимых адресов, на которые мы будем заходить по ssh при помощи собственно expect.
Также необходимо помнить, что стандартно скрипт выпадает при возникновении первой же ошибки, например неответе компьютера клиента, и наверное стоит поискать способ обработки таких исключений.
Скрипт
Сообщаем, что для выполнения нам необходимо использовать нестандартный интерпретатор
#!/usr/bin/expect -f
Задаём паузу для ожидания ответа с клиента, имя пользователя и пароль (это скорее по инерции из имеющихся в сети примеров):
set timeout 2
set USER «u1»
set PASS «1»
Начало сценария:
while 1 { // применение цикла с предусловием
foreach HOST {58 60 61} { // применение цикла с параметром для списка окончаний адресов. Да, их можно генерировать и автоматически, но пост не об этом
spawn ssh $USER@192.168.0.$HOST // подключаемся
expect {
"(yes/no)?*" {
send «yesr» // не забывайте про r в конце строки, перед кавычками. Иначе волшебства не получится
}
}
expect «word:»
send "$PASSr"
expect "$*"
send «killall -r teew*r»
expect "$*"
send «killall firefoxr»
expect "$*"
send «killall chromer»
expect "$*"
send «exitr»
expect eof
}
Это был простой скрипт автоубивания ненужных процессов для гимназии. В своём же кабинете я модифицировал скрипт и для автовыключения машин:
guest@0-315-gymn2 ~ $ cat scripty
#!/usr/bin/expect -f
set timeout 2
set USER «user»
set HOST «2»
set PASS «2357»
# Начало сценария
while 1 {
foreach HOST {2 3 5 7} {
spawn ssh $USER@192.168.0.$HOST
expect {
"(yes/no)?*" {
send «yesr»
}
}
expect «word:»
send "$PASSr"
expect "$*"
send «sur»
expect «word:*»
send «supasswordr»
expect "#*"
send "/sbin/shutdown 0 -hPr"
expect "#*"
send «exitr»
expect "$*"
send «exitr»
expect eof
}
}
Заключение
Надеюсь, упоминание замечательного интерпретатора expect и пара живых примеров по работе с ним будут полезны сообществу и породят немало статей о более тонких его применениях.
P.S.:
Скрипт автопоиска активных компьютеров и создания списка адресов для обработки чуть позже написал один мой ученик (не делать же всё интересное самому). Чуть позже, когда заслужит инвайт, он сможет сам написать об этом в применении к более интересной задаче.
Автор: cronoc