Читать переменную в bash со значением по умолчанию

192

Мне нужно прочитать значение из терминала в скрипте bash. Я хотел бы иметь возможность предоставить значение по умолчанию, которое пользователь может изменить.

# Please enter your name: Ricardo^

В этом скрипте приглашение «Пожалуйста, введите ваше имя»: значение по умолчанию - «Рикардо», а курсор будет после значения по умолчанию. Есть ли способ сделать это в скрипте bash?

Рикардо Маримон
источник

Ответы:

280

Вы можете использовать расширение параметров, например

read -p "Enter your name [Richard]: " name
name=${name:-Richard}
echo $name

Включение значения по умолчанию в подсказку между скобками является довольно распространенным соглашением

ghostdog74
источник
7
Я закончил тем, что делал что-то на основе этого. Чтение во временную переменную inputи затем использование name=${input:-$name}.
Рикардо Маримон
41
Это на самом деле не отвечает на вопрос. Значение по умолчанию должно отображаться в приглашении.
Доктор Человек Персонал II
3
а что будет name=${!input:-$name}делать?
Гарри Ли
8
@ Dr.PersonPersonII - вы можете добавить значение по умолчанию, выполнив что-то вроде этого: read -p "Введите имя удаленного хоста [$ remote_host_default]:" remote_host remote_host = $ {remote_host: - $ remote_host_default}
Доблер
5
$1становится${1:-some_default_string}
ThorSummoner
162
read -e -p "Enter Your Name:" -i "Ricardo" NAME

echo $NAME
Джадав Бхеда
источник
1
Отличный ответ! Я просто хочу упомянуть, что у меня были проблемы с этим, потому что я не видел промежуток между "Рикардо" и ИМЯ, но однажды я понял это ... волшебство ! Спасибо!
Мистер Миккель
40
к сожалению, -i это недопустимый параметр для OSX 10.7
undefined
3
@BrianMortenson Вы можете обновить bash, используя homebrew: stackoverflow.com/questions/16416195/…
antonagestam
2
Этот ответ показывает, как заставить эту работу работать в OS X (Bash 3.x): stackoverflow.com/questions/22634065/…
Кристоф Петшниг,
3
Просто отметьте, что, по- -eвидимому, необходимо разрешить -iфактически работать
MestreLion
49

В Bash 4:

name="Ricardo"
read -e -i "$name" -p "Please enter your name: " input
name="${input:-$name}"

Это имя отображается после приглашения, как это:

Please enter your name: Ricardo

с курсором в конце имени и позволяет пользователю редактировать его. Последняя строка является необязательной и заставляет имя быть исходным по умолчанию, если пользователь удаляет ввод или значение по умолчанию (отправляя нулевое значение).

Приостановлено до дальнейшего уведомления.
источник
Не могу использовать bash4, потому что он нестандартен в дистрибутивах Debian. Мне нужно что-то, что будет работать без особых хлопот.
Рикардо Маримон
1
нет необходимости в последней строке кода, просто использовать nameвместо inputв readкоманде.
РНК
2
@RNAer: при использовании дополнительной переменной значение $nameсохраняется, если пользователь удаляет предложенное значение (и, следовательно, вводит пустую строку). Все зависит от того, что вам нужно. Я сказал так же в своем ответе. Вы правы, однако, что я мог бы быть более явным и сказал, что, если бы необязательная строка не использовалась, переменная могла бы быть name.
Приостановлено до дальнейшего уведомления.
1
@DennisWilliamson: Вы правы. Это хорошая практика, если ты этого хочешь.
РНК
16

Код:

IN_PATH_DEFAULT="/tmp/input.txt"
read -p "Please enter IN_PATH [$IN_PATH_DEFAULT]: " IN_PATH
IN_PATH="${IN_PATH:-$IN_PATH_DEFAULT}"

OUT_PATH_DEFAULT="/tmp/output.txt"
read -p "Please enter OUT_PATH [$OUT_PATH_DEFAULT]: " OUT_PATH
OUT_PATH="${OUT_PATH:-$OUT_PATH_DEFAULT}"

echo "Input: $IN_PATH Output: $OUT_PATH"

Образец прогона:

Please enter IN_PATH [/tmp/input.txt]: 
Please enter OUT_PATH [/tmp/output.txt]: ~/out.txt
Input: /tmp/input.txt Output: ~/out.txt
manish_s
источник
Мне это нравится, потому что оно следует соглашению, которое я вижу во многих сценариях оболочки, где значение по умолчанию заключено в квадратные скобки перед двоеточием. Спасибо!!!
морфический
16

Я нашел этот вопрос, ища способ представить что-то вроде:

Something interesting happened.  Proceed [Y/n/q]:

Используя приведенные выше примеры, я вывел это:

echo -n "Something interesting happened.  "
DEFAULT="y"
read -e -p "Proceed [Y/n/q]:" PROCEED
# adopt the default, if 'enter' given
PROCEED="${PROCEED:-${DEFAULT}}"
# change to lower case to simplify following if
PROCEED="${PROCEED,,}"
# condition for specific letter
if [ "${PROCEED}" == "q" ] ; then
  echo "Quitting"
  exit
# condition for non specific letter (ie anything other than q/y)
# if you want to have the active 'y' code in the last section
elif [ "${PROCEED}" != "y" ] ; then
  echo "Not Proceeding"
else
  echo "Proceeding"
  # do proceeding code in here
fi

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

sibaz
источник
Очень хорошо. Можно даже немного улучшить, чтобы повторить вопрос, если кто-то просто вводит «k» или что-то еще, кроме заданных вариантов.
erikbwork
1
Я только что написал этот комментарий после поцарапанного зуда. Теперь у меня есть функция оболочки, которая включает в себя все вышеперечисленное, и я склонен использовать это. Кажется, что Shell не работает хорошо, поэтому я стараюсь избегать этого. Я мог бы проверить результат своей функции и дать еще одну попытку, но в основном я пишу инструменты администратора, где что-то может пойти не так, поэтому я хочу, чтобы администратор мог в любой момент аккуратно остановить скрипт.
Сибаз
11

Я только что использовал этот шаблон, который я предпочитаю:

read name || name='(nobody)'
bukzor
источник
6
name=Ricardo
echo "Please enter your name: $name \c"
read newname
[ -n "$newname" ] && name=$newname

Установить значение по умолчанию; распечатать его; прочитать новое значение; если есть новое значение, используйте его вместо значения по умолчанию. Существуют (или были) некоторые различия между оболочками и системами в том, как подавить перевод строки в конце приглашения. Нотация \ c, кажется, работает на MacOS X 10.6.3 с 3.x bash и работает на большинстве вариантов Unix, производных от System V, с использованием оболочек Bourne или Korn.

Также обратите внимание, что пользователь, вероятно, не осознает, что происходит за кулисами; их новые данные будут введены после того, как имя уже на экране. Может быть, лучше отформатировать его:

echo "Please enter your name ($name): \c"
Джонатан Леффлер
источник
printfболее портативен, чемecho
ghostdog74
3
@ ghostdog74: может быть и так; тем из нас, кто изучил программирование оболочки более 25 лет назад, трудно понять, какие из наших практик по-прежнему актуальны. Похоже, что bash переписал почти все. Я знаю, что printf некоторое время использовался как команда, хотя я очень редко ее использую (вероятно, никогда?). У меня такое впечатление, что я должен заткнуться на раковину, пока я не научился (пере) изучать удар. «Это смешно; В программном обеспечении, над которым я работаю, есть сценарии оболочки, которые не работают должным образом, но проблема не в крушении. Я просто сыт по горло исправлениями ' if (test -z "$xxx"); ...' и другими C-оболочками.
Джонатан Леффлер
Я поражен, что bash поддерживает \c, так как он также поддерживает echo -n! Тем не менее, вы должны добавить, -eчтобы получить эхо Bash для интерпретации побегов. Я думаю, \cчто для вещей, оставшихся недосказанными:echo -e "Syntax slightly off\c, but I've learned so much from what you've shared. Thanks, @JonathanLeffler!"
jpaugh
@Jonathan Leffler К сожалению, не совсем то, о чем просил OP, по крайней мере, не в моей версии bash 4.x $ bash --version GNU bash, version 4.3.33(0)-release a) «Я хотел бы иметь возможность предоставить значение по умолчанию, которое пользователь может изменить». Ваш echo "Please enter your name: $name \c"не позволяет мне редактировать значение по умолчанию. б) "и курсор будет после значения по умолчанию." Также не соответствует действительности ... Ответ @Paused до дальнейшего уведомления. выполняет оба требования.
Берни Райтер
1
#Script for calculating various values in MB
echo "Please enter some input: "
read input_variable
echo $input_variable | awk '{ foo = $1 / 1024 / 1024 ; print foo "MB" }'
Кокан
источник
3
пожалуйста, добавьте объяснение к вашему ответу.
Суфиян Гори
-1

Параметр -e и -t не работают вместе. Я попробовал некоторые выражения, и в результате был следующий фрагмент кода:

QMESSAGE="SHOULD I DO YES OR NO"
YMESSAGE="I DO"
NMESSAGE="I DO NOT"
FMESSAGE="PLEASE ENTER Y or N"
COUNTDOWN=2
DEFAULTVALUE=n
#----------------------------------------------------------------#
function REQUEST ()
{
read -n1 -t$COUNTDOWN -p "$QMESSAGE ? Y/N " INPUT
    INPUT=${INPUT:-$DEFAULTVALUE}
    if  [ "$INPUT" = "y" -o "$INPUT" = "Y" ] ;then
        echo -e "\n$YMESSAGE\n"
        #COMMANDEXECUTION
    elif    [ "$INPUT" = "n" -o "$INPUT" = "N" ] ;then
        echo -e "\n$NMESSAGE\n"
        #COMMANDEXECUTION
    else
        echo -e "\n$FMESSAGE\n"
    REQUEST
    fi
}
REQUEST
speefak
источник
Ваш ответ не имеет ничего общего с вопросом, не так ли?…
gniourf_gniourf
Это обходной путь для использования параметров -e и -t. эта кодовая строка (-e и -i для значения по умолчанию): read -e -p "Введите ваше имя:" -i "Рикардо" NAME не работает с обратным отсчетом времени (-t)
speefak
Да, но это не вопрос в вопросе, не так ли?
gniourf_gniourf
3
Что вы можете сделать, это задать новый вопрос и ответить на него самостоятельно ;). Это разрешено на ТАК! но мы не хотим загрязнять другие вопросы несвязанными вещами.
gniourf_gniourf