Толик Панков
hex_laden
............ .................. ................

October 2025
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Толик Панков [userpic]
Простой интерактив в bash-скриптах

Преамбула


Иногда полезно иметь в своих скриптах элемент интерактивного взаимодействия с пользователем, например, запросить с клавиатуры некую строку (путь, пароль, имя пользователя и т.д.), или получить от пользователя подтверждение действия (Вы уверены? [Y/n]). Далее покажу простейшие случаи.

Ввод строки


Все, кто хоть раз пользовался для создания нового пользователя скриптом adduser, наблюдали на экране следующую картину:

Login name for new user []: wolfkid

User ID ('UID') [ defaults to next available ]:

Initial group [ users ]:
...
Home directory [ /home/wolfkid ]

Shell [ /bin/bash ]

Expiry date (YYYY-MM-DD) []:


Понятно, что где-то можно (и нужно) ввести свои данные, а где-то согласиться с предлагаемыми скриптом по умолчанию (или не согласиться, ввести свое).

Вопрос, как такое сделать в своем скрипте?

В данном случае можно воспользоваться командой read.

Общий синтаксис:

read [ПАРАМЕТРЫ] [ПЕРЕМЕННАЯ]

Если имя переменной не будет указано, то, что было введено с клавиатуры попадет в специальную переменную $REPLY.

Обратите внимание: в команду read имя переменной подставляется без символа $. Т.е. если вы хотите, чтоб введенная строка оказалась в переменной VAR1, то синтаксис такой:

read VAR1

Функция для ввода строки с возможностью оставить значение по умолчанию.


Напишем функцию, которая будет принимать два параметра - строку с пояснением, что мы хотим, чтоб пользователь ввел, и строку, которая будет представлять значение по умолчанию. В случае, если пользователь что-то ввел, то функция запишет в переменную $STR_RESULT новое значение. Если же пользователь просто нажмет Enter, то в $STR_RESULT будет записано значение, переданное во втором параметре.

ask_string() #1-user ask string, #2-default variant
{
    read -r -p "$1 [$2]:"
    
    if [ -z "$REPLY" ]; then
	if [ -n "$2" ]; then
	    STR_RESULT=$2
	fi
    else
	STR_RESULT=$REPLY
    fi
}


Небольшое пояснение по используемым параметрам read:

-r - отключает режим интерпретации эскейп-последовательностей, т.е. \n, \r, \t и т.д. не будут записаны в переменную, как символы возврата каретки, перевода строки или табуляции, а будут восприниматься, как символьные последовательности - слэш и буква.
-p [СООБЩЕНИЕ] - СООБЩЕНИЕ, это строка, которая будет выведена пользователю перед тем, как он сможет ввести данные.

Пример вызова функции:

ask_string "Select path" "/home/smallwolfie/test/testdir"
echo $STR_RESULT


Вывод:
Пользователь нажал Enter, оставив значение по умолчанию:
smallwolfie@wolfschanze:~/test/input01$ ./askstring
Select path [/home/smallwolfie/test/testdir]:
/home/smallwolfie/test/testdir


Пользователь ввел другое значение:
smallwolfie@wolfschanze:~/test/input01$ ./askstring
Select path [/home/smallwolfie/test/testdir]:/tmp
/tmp


Готовый скрипт на GitHub
Готовый скрипт на PasteBin

Запрос Да/Нет


Обычный запрос Вы уверены [Y/N]. Для удобства использования (т.е. копипаста в другие скрипты) тоже можно реализовать в виде отдельной функции, которой передается один параметр - строка с вопросом для пользователя:

ask_y_n() #$1 - question
{
    echo -n "$1 [Y/N]: "
    while [ 1 -eq 1 ];do
	read -s -n1
	
	case "$REPLY" in
	    [yY])
		echo
		return 0
	    ;;
	    [nN])
		echo
		return 1
	    ;;
	esac
    done
}


Пояснения:

1. Командой echo -n "$1 [Y/N]: " выводим пользователю сообщение с пояснением, что надо нажать (Y или N). Параметр -n в команде echo запрещает ей переводить курсор на новую строку. Опцией -p команды read не пользуемся для красоты, иначе сообщение будет выскакивать при каждом нажатии клавиши, и заполнять экран.
2. Организуем бесконечный цикл:
while [ 1 -eq 1 ];do
#...
done

Единица всегда равна единице, поэтому цикл не завершится, если не будет какого-то прерывания внутри цикла.
3. В начале цикла вставляем команду read со следующими параметрами:
-s - не отображать вводимые пользователем символы на экране
-n1 - читать 1 символ, и завершаться, не дожидаясь нажатия клавиши Enter.
4. Далее в операторе case проверяем, что было нажато: если Y или y, то пользователь ответил "да", если N или n - "нет". Ну не заставлять же пользователя регистр символов отдельно проверять... Возвращаем соответствующий код возврата 0 для "да", 1 для "нет"

Пример вызова функции:

ask_y_n "Run it?"

if [ "$?" -eq 0 ];then
    echo "User replied YES!"
else
    echo "User replied NO :("
fi


Вывод:

Пользователь не нажал ничего, или нажал что-нибудь кроме YyNn:

smallwolfie@wolfschanze:~/test/input02$ ./askyn
Run it? [Y/N]:


Пользователь ответил "Нет":
smallwolfie@wolfschanze:~/test/input02$ ./askyn
Run it? [Y/N]:
User replied NO :(


Пользователь ответил "Да":

smallwolfie@wolfschanze:~/test/input02$ ./askyn
Run it? [Y/N]:
User replied YES :)


Скрипт на GitHub
Скрипт на PasteBin

Источники


Внутренние команды bash

Это репост с сайта http://tolik-punkoff.com
Оригинал: http://tolik-punkoff.com/2019/05/11/prostoj-interaktiv-v-bash-skriptah/

Tags: ,
Comments

а ты как-нибудь послушай на трубе не-нативов — охуеешь: там натуральный мгимо финишд. и ничего — понимают. точно так же: если читать по «школьным правилам» — народ немного охуеет, но в принципе поймёт. а то и сам так разговаривает.

на самом деле одна фигня в обоих языках: не знаешь, как слово пишется — хуй на слух правильно запишешь. не знаешь, как читается — хуй правильно прочитаешь. ну вот то же «прочитаешь» — никто не говорит мягкое «ш» в конце, надо тупо зазубрить, что там есть мягкий знак, но в устной речи его нет. ты просто к русскому привык, и тебе кажется, что он проще. если попробуешь немного абстрагироваться и представить, что ты русского не знаешь, то охуеешь знатно. собственно, дети (и некоторая молодежь) как раз «пишут как слышат» — и получается ядрёный бред, который часто надо тупо дешифровать (особенно если они ещё и не очень знают, как произносится).

и в русском словообразовании логики нихера, например. «а вот тут у нас смягчение, но вот тебе куча исключений, где нет. а тут вот согласная выпадает, но не всегда.» и так далее. в английском на самом деле с этим намного проще: общеупотребительных неправильных глаголов пара десятков от силы, остальное делается чисто механически, за счёт аналитичности языка.

и есть ещё один мощный финт, которого отчего-то многие боятся: не выёбываться. не помнишь слово, не уверен в конструкции — нахуй её, тупо опиши словами попроще. ну, типа, забыл, как будет «морг»? и хер с ним, это you know, that place where they put dead people. некрасиво? конечно, премию по литературе не получишь. зато работает.

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

Ну да, вспоминаю, как мы всем кагалом исправляли товарищу (нативу) русская языка. Он не только в слове "еще" делал 4 ошибки, у него была коронное слово "вкрации" (оказалось, что это "вкратце"), от которого даже у меня уши дыбом шевелились, "толи" ("то ли"), не говоря уж о -тся/ться и массе "проезжающих в поезде слетевших шляп", причем даже в устной речи.

Словообразование и прочая внутренняя механика языка в английском и впрямь вроде попроще, чем в русском, а вот буквосочетания, и что хуже - когда буква тут читается, как У, а тут, как "жопа паровоза" - вот это пиздец.

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