Взаимодействие bash-скриптов с пользователем. Часть 2

    Наша программа настолько сурова, что даже логин отображается звездочками (bash.org.ru)

    Вашему вниманию представляется новая подборка средств общения скриптов с пользователем. Надеюсь, интересно будет всем, кто не боится работать с консолью.
    Первую часть можно найти тут.

    Опции (ключи)


    Этот способ был достоин первой части статьи, но не попал туда из-за забывчивости автора. Несомненно, этот способ знаком всем пользователям *nix, хоть раз работавших с консолью. Простой наглядный пример:

    Плюс в том, что ключи короткие и их можно комбинировать. Попытаемся сделать что-нибудь подобное, а за одно изучим еще несколько моментов.
    #!/bin/bash
    set -e
    
    ME=`basename $0`
    function print_help() {
        echo "Работа с файлом test_file"
        echo
        echo "Использование: $ME options..."
        echo "Параметры:"
        echo "  -c          Создание файла test_file."
        echo "  -w text     Запись в файл строки text."
        echo "  -r          Удаление файла test_file."
        echo "  -h          Справка."
        echo
    }
    
    function create_file() {
        touch test_file
    }
    
    function write_to_file {
        echo "$TEXT" >> test_file
    }
    
    function remove_file {
        rm test_file
    }
    
    # Если скрипт запущен без аргументов, открываем справку.
    if [ $# = 0 ]; then
        print_help
    fi
    
    while getopts ":cw:r" opt ;
    do
        case $opt in
            c) create_file;
                ;;
            w) TEXT=$OPTARG;
                write_to_file
                ;;
            r) remove_file
                ;;
            *) echo "Неправильный параметр";
                echo "Для вызова справки запустите $ME -h";
                exit 1
                ;;
            esac
    done
    

    Итак, что мы имеем?
    • Команда set -e остановит скрипт, если при его выполнении возникнет ошибка (подробнее о других опциях здесь).
    • Основные операции скрипта упакованы в функции. Конечно, глупо помещать в функции по одной команде, но это лишь для примера, в реальности их может быть ну очень много.
    • Функция getopts разбирает переданные аргументы. За ней перечисляются допустимые опции. Двоеточие после опции 'w' означает, что c данной опцией идет дополнительный аргумент, который помещается в переменную $OPTARG.
    • Опции можно комбинировать, но стоит учитывать то, что они выполняются по порядку. Это значит, что если мы выполним script -rc то сначала файл будет удален, а затем создан. При этом, если файла не существовало, то скрипт завершится с ошибкой, не дойдя до создания файла.
    • Также стоит учитывать то, что после ключа 'w' обязательно должен следовать аргумент. Если он будет отсутствовать, то скрипт выполнит опцию '*' (по умолчанию). Интересно, что если запустить script -wr Hallo, то опция 'r' будет воспринята как дополнительный параметр к опции 'w', а 'Hallo' проигнорировано. Правильно будет script -w Hallo -r

    Подробнее о getopts можно узнать здесь.

    Выбор


    В предыдущей статье я рассматривал выбор варианта выполнения с помощью case. А сейчас рассмотрим создание меню с помощью конструкции select, которая позволяет создать простые нумерованные меню.
    #!/bin/bash
    
    # Изменение строки приветствия
    PS3='Выберите операционную систему: '
    
    select OS in "Linux" "Windows" "Mac OS" "BolgenOS"
    do
      echo
      echo "Вы выбрали $OS!"
      echo
      break
    done
    


    Подробнее описано здесь.

    Логирование


    Бывает удобно не выводить сообщения на экран, а записывать их в лог-файл. Особенно если скрипт запускается при старте системы.
    Для этого можно использовать обычную запись в файл.
    #!/bin/bash
    
    NAME=`basename $0`
    TIME=`date +%F\ %H:%M:%S`
    TYPE='<info>'
    
    echo "$TIME $NAME: $TYPE Operation completed successfully" >> /tmp/log
    

    Но есть и специальный инструмент ведения логов — logger.
    logger Operation completed successfully
    sudo tail /var/log/syslog
    

    Подробнее тут.

    Оповещения на рабочем столе



    Немножко развлечемся и поиграемся с нотиферами. Для начала поставим нужный пакет:
    sudo apt-get install libnotify-bin
    

    Теперь выполним простейший пример прямо в терминале:
    notify-send --expire-time=10000 "Привет" "Я слежу за тобой"
    

    Об этом уже писали на Хабре.

    Клавиатурные индикаторы


    Хотите поморгать лампочками на клавиатуре? Да, пожалуйста!
    #!/bin/bash
    
    setleds -D +caps < /dev/tty7
    sleep 1
    setleds -D -caps < /dev/tty7
    

    Скрипт необходимо запускать с правами рута!

    Звуковые сигналы


    Звуковые сигналы можно подавать несколькими способами:
    • С помощью управляющей последовательности на системный динамик
      echo -e "\a"
      
    • С помощью утилиты beep
      beep 659 120
      
    • Консольными плеерами, например aplay, mplayer и т.д.
    • Синтезатором речи.

    Первые два способа у меня не сработали, скорее всего из-за настроек терминала.

    Открытие/закрытие сидирома


    #!/bin/bash
    # открыть сидиром
    eject
    # закрыть сидиром
    eject -t
    

    «Это не интерфейс!» — скажете вы. Но факты доказывают обратное.
    Поделиться публикацией

    Комментарии 17

      +4
      Первые два способа у меня не сработали, скорее всего из-за настроек терминала.
      Если у вас Ubuntu или что-то ещё, то PC-спикер отключён в ядре чёрным списком /etc/modprobe.d/blacklist.conf. Цитата, с которой я полностью согласен:
      # ugly and loud noise, getting on everyone's nerves; this should be done by a
      # nice pulseaudio bing (Ubuntu: #77010)
      blacklist pcspkr
        +2
        Я тоже согласен
          +1
          Идиотизм, на том же основании можно /dev/console запретить. А что, есть же nice gnome/kde…
          0
          Bell обычно выводится как-то так:
          echo -e '\a'

          Зачем там у вас доллар — никак не пойму.

          select — это зверский башизм, не стоит его использовать. Если уж так хочется интерактива — то любой из вариантов dialog выглядит и работает на порядке адекватнее.
            +2
            Bash заявлен в названии статьи, так что башизм вполне уместен.
            А dialog — это вообще отдельный пакет.
              +2
              Уместен-то уместен, но учитывая нацеленность статьи на в целом начальный уровень — я бы все-таки обосновывал его применение — а здесь явно смысла использовать именно bash никакого. А так — особенно для новичков — bash довольно медленный и местами сильно странно себя ведет — в отличие от sh (dash, ash), которые весьма близко соответствуют стандарту.

              А что до dialog — он входит в basesystem всех известных мне современных ОС — правда, возможно, в весьма покоцанном виде. Чего, кстати, совсем не скажешь о bash — на многих не-GNU системах он по умолчанию не устанавливается.
                +1
                Dialog описывался в первой части. Кстати есть такая штука, как whiptail, которая в большинстве случаев стоит по дефолту.
                Иногда использовать псевдографику не очень оправдано.
                На счет портируемости — да, не подумал. Но с необходимостью использовать скрипты на без bash-ных системах не встречался. В любом случае, выбор инструмента за вами.
                  +1
                  Первую часть помню, за ее написание — спасибо :)

                  Но в целом, субъективно, основная проблема написания на sh/bash — решить, нужно ли на нем это писать или не нужно. В некоторых случаях (и почти все интерактивные случаи относятся в основном сюда) лучше написать на каком-то другом скриптовом языке, а в некоторых случаях — наоборот, shell scripting себя оправдывает — и тогда нужно выбирать между sh и bash. У bash есть несколько killer features (таких, как pipefail, хитрые глоббинги, гораздо более богатые substitutions, pushd/popd, массивы или интерактивный режим), но далеко не всегда лучше выбирать его (и уж если выбирать — то осознанно).
                    0
                    Люди разные. Кому-то проще писать скрипты на питоне/перле, а кому-то хочется писать на sh/bash. ИМХО в Linux bash как-то нативнее, что ли…
                    Но спасибо за информацию, буду думать :)
                      +2
                      Вопрос не в людях, а, в первую очередь, в задачах. Я уже многие годы бьюсь и хочу хоть как-то для себя сформулировать четкие принципы — когда стоит решать задачу каким подходом и инструментом.

                      Про shell я по крайней мере понял, что четкое «нет» — это любые алгоритмически-нагруженные вещи.
                      Поэтому как только число переменных становится больше десятка, хочется заводить всякую объектно-ориентированность, массивы, сложные структуры данных и т.д. — это такая лакмусовая бумажка, хороший индикатор того, что shell нужно оставлять и переходить к скриптовым языкам.

                      Четкое «да» и показание к применению — когда то, что пишешь занимается ровно тем, для чего нужны shell scripts — запускать другие программы — и иногда какая-то минимальная логика, связывающая эти запуски. Из shell может быть вполне удобно запускать программы довольно сложными способами (в background, pool'ом worker'ов, с разными приоритетами, очередями, с привязкой к разным процессорам и т.п.). make (если можно считать его частью shell scripting) и xargs местами *здорово* облегчают жизнь.

                      Четкое «да» — когда нужно много прыгать с машины на машину через ssh и делать тем самым некую распределенную систему.

                      А вот по поводу всяких пограничных случаев — сильно не уверен, несмотря на то, что shell все познаю и познаю потихоньку… года с 98-го, наверное?.. или 97?..
                        0
                        Спасибо, хорошо сформулировал.
                          0
                          Эм %) Я как раз думал, что нифига не сформулировал — я только 2-3 примера привел, когда решение очевидно и все…
                          0
                          Стоит разделить понятие скрипт и программа. Скрипт по определению не может быть большим и сложным. Он должен выполнять конкретную задачу, в большинстве случаев — облегчение рутинных операций.
                            0
                            Я как-то разделение с трудом представляю — по крайней мере для себя… Если у меня работа такая — автоматизировать рутинные операции? И через пару-тройку месяцев сборище скриптиков по 3-4 строчки, которых пишешь десятки в день, начинает превращаться в какие-то фреймворки, с своей системой библиотек, зависимостей — это уже программа или нет?
              0
              echo "…" >> /var/log/syslog
              Не делайте так НИКОГДА. В файл /var/log/syslog уже пишет один процесс (сам syslogd), а когда в один файл пишут несколько процессов в файле образуется мешанина из записанных в него данных (одни частично перекрывают другие). Ибо нет у нас гарантии, что и syslogd и bash открывали этот файл с флагом O_APPEND. Хотите что-то записать в syslog — пишите в /dev/log (через socat) или через утилиту logger.

              setleds -D +caps < /dev/tty7
              Скрипт необходимо запускать с правами рута!
              Врядли для этого нужен root. Скорее просто нужны права на запись в /dev/tty*. В некоторых дистрибутивах для этого достаточно добавить пользователя в группу tty, в других можно к примеру при загрузке системы изменить владельца или права доступа к всё равно неиспользуемому /dev/tty63, тогда даже в cron-скриптах можно будет beep-ать и мигать лампочками через >/dev/tty63.
                0
                Спасибо за пояснения.
                +1
                Спасибо! Полезные статьи, именно как пинок в нужном направлении :)

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое