Odczytaj zmienną bash z wartością domyślną

191

Muszę odczytać wartość z terminala w skrypcie bash. Chciałbym móc podać wartość domyślną, którą użytkownik może zmienić.

# Please enter your name: Ricardo^

W tym skrypcie monit brzmi „Proszę podać swoje imię:” wartością domyślną jest „Ricardo”, a kursor będzie znajdować się za wartością domyślną. Czy jest na to sposób w skrypcie bash?

Ricardo Marimon
źródło

Odpowiedzi:

280

możesz użyć rozszerzenia parametrów np

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

Umieszczanie wartości domyślnej w pytaniu między nawiasami jest dość powszechną konwencją

ghostdog74
źródło
7
Skończyło się na zrobieniu czegoś na tej podstawie. Odczyt do zmiennej temp, inputa następnie użycie name=${input:-$name}.
Ricardo Marimon,
41
To nie odpowiada na pytanie. Wartość domyślna powinna zostać wyświetlona w monicie.
Dr. Person Person II
3
a co name=${!input:-$name}zrobisz
Harry Lee,
8
@ Dr.PersonPersonII - możesz dodać wartość domyślną, wykonując coś takiego: czytaj -p "Wpisz nazwę zdalnego hosta [$ remote_host_default]:" remote_host remote_host = $ {remote_host: - $ remote_host_default}
Dobler
4
$1zostaje${1:-some_default_string}
ThorSummoner
160
read -e -p "Enter Your Name:" -i "Ricardo" NAME

echo $NAME
Jadav Bheda
źródło
1
Świetna odpowiedź! Chciałbym tylko wspomnieć, że miałem z tym problem, ponieważ nie widziałem odstępu między „Ricardo” a NAME, ale kiedy to odkryłem… magia ! Dziękuję Ci!
Pan Mikkél,
40
niestety -i nie jest prawidłową opcją dla OSX 10.7
niezdefiniowany
3
@BrianMortenson Możesz zaktualizować bash za pomocą homebrew: stackoverflow.com/questions/16416195/…
antonagestam
2
Ta odpowiedź pokazuje, jak to zrobić w systemie OS X (Bash 3.x): stackoverflow.com/questions/22634065/…
Christoph Petschnig
3
Zauważ, że -ewydaje się to obowiązkowe, aby pozwolić -ina faktyczne działanie
MestreLion
48

W Bash 4:

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

Wyświetla nazwę po monicie w następujący sposób:

Please enter your name: Ricardo

z kursorem na końcu nazwy i pozwala użytkownikowi ją edytować. Ostatni wiersz jest opcjonalny i wymusza, aby nazwa była oryginalną wartością domyślną, jeśli użytkownik usunie dane wejściowe lub wartość domyślną (przesłanie wartości null).

Wstrzymano do odwołania.
źródło
Nie można użyć bash4, ponieważ nie jest standardem w dystrybucjach Debiana. Potrzebuję czegoś, co zadziała bez większych problemów.
Ricardo Marimon,
1
nie potrzebujesz ostatniego wiersza kodu, po prostu użyj namezamiast inputw readpoleceniu.
RNA,
1
@ RNAer: Przy użyciu dodatkowej zmiennej wartość $namezostaje zachowana, jeśli użytkownik usunie proponowaną wartość (a tym samym wprowadzi ciąg zerowy). Wszystko zależy od twoich potrzeb. Powiedziałem tak samo w swojej odpowiedzi. Masz jednak rację, że mógłbym być bardziej wyraźny i powiedziałem, że gdyby nie użyto linii opcjonalnej, zmienna mogłaby być name.
Wstrzymano do odwołania.
1
@DennisWilliamson: Masz rację. Jest to dobra praktyka, jeśli tego się chce.
RNA,
16

Kod:

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"

Przykładowy przebieg:

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
źródło
Podoba mi się to, ponieważ jest zgodne z konwencją, którą widzę w wielu skryptach powłoki, w których domyślną wartością jest nawias kwadratowy przed dwukropkiem. Dzięki!!!
morfatyczny
16

Znalazłem to pytanie, szukając sposobu na przedstawienie czegoś takiego:

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

Na podstawie powyższych przykładów wydedukowałem to:

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

Mam nadzieję, że pomoże to komuś nie myśleć o logice, jeśli napotka ten sam problem

Sibaz
źródło
Bardzo dobrze. Można nawet trochę poprawić, by powtórzyć pytanie, jeśli ktoś wpisze „k” lub coś innego niż podane opcje.
erikbwork
1
Właśnie napisałem ten komentarz po zadrapaniu. Mam teraz funkcję powłoki, która obejmuje powyższe i zwykle z niej korzystam. Shell wydaje się nie zapętlać, więc staram się tego unikać. Mogę przetestować wynik mojej funkcji i spróbować jeszcze raz, ale w zasadzie piszę narzędzia administracyjne, w których może się nie udać, więc chcę, aby administrator mógł w dowolnym momencie całkowicie zatrzymać skrypt.
Sibaz
11

Właśnie użyłem tego wzoru, który wolę:

read name || name='(nobody)'
bukzor
źródło
6
name=Ricardo
echo "Please enter your name: $name \c"
read newname
[ -n "$newname" ] && name=$newname

Ustaw domyślne; Wydrukuj to; przeczytaj nową wartość; jeśli jest nowa wartość, użyj jej zamiast wartości domyślnej. Istnieją (lub były) różnice między powłokami i systemami dotyczące sposobu pomijania znaku nowej linii na końcu monitu. Notacja „\ c” wydaje się działać na MacOS X 10.6.3 z bash 3.x i działa na większości wariantów Uniksa pochodzących z Systemu V, przy użyciu powłok Bourne'a lub Korna.

Zauważ też, że użytkownik prawdopodobnie nie zda sobie sprawy z tego, co dzieje się za kulisami; ich nowe dane zostaną wprowadzone po nazwie już na ekranie. Może być lepiej sformatować:

echo "Please enter your name ($name): \c"
Jonathan Leffler
źródło
printfjest bardziej przenośny niżecho
ghostdog74
3
@ ghostdog74: może tak; ci z nas, którzy nauczyli się programowania powłoki ponad 25 lat temu, mają trudności z ustaleniem, które z naszych praktyk są nadal aktualne. Coraz częściej wygląda na to, że bash przepisał prawie wszystko. Wiem, że printf istnieje od jakiegoś czasu jako polecenie - jednak bardzo rzadko go używam (prawdopodobnie - nigdy?). Mam wrażenie, że powinienem zamknąć się na powłoce, dopóki (ponownie) nie nauczę się bash. „To zabawne; oprogramowanie, na którym pracuję ma skrypty powłoki, które nie działają dobrze - ale problemem nie są bash-isms. Mam po prostu dość naprawiania ' if (test -z "$xxx"); ...' i innych skorupiaków C.
Jonathan Leffler
Dziwi mnie, że bash obsługuje \c, ponieważ obsługuje również echo -n! Musisz jednak dodać, -eaby echo basha interpretowało ucieczki. Chyba \cchodzi o rzeczy, które pozostały niewypowiedziane:echo -e "Syntax slightly off\c, but I've learned so much from what you've shared. Thanks, @JonathanLeffler!"
jpaugh
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" }'
kokane
źródło
3
dodaj wyjaśnienie do swojej odpowiedzi.
Sufiyan Ghori
-1

Parametr -e i -t nie działają razem. wypróbowałem niektóre wyrażenia i wynik był następujący fragment kodu:

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
źródło
Twoja odpowiedź nie ma wiele wspólnego z pytaniem, prawda?…
gniourf_gniourf
jest to obejście dla używania parametru -e i -t. ten kodeline (-e i -i dla wartości domyślnej): czytaj -e -p "Wpisz swoje imię:" -i "Ricardo" NAZWA nie działa z countdowntimer (-t)
speefak
Tak, ale nie jest to zadawane w pytaniu, prawda?
gniourf_gniourf
3
Możesz zadać nowe pytanie i sam na nie odpowiedzieć ;). Jest to dozwolone na SO! ale nie chcemy zanieczyszczać innych pytań niepowiązanymi rzeczami.
gniourf_gniourf