Jak monitować o wprowadzenie Tak / Nie / Anuluj w skrypcie powłoki systemu Linux?
1443
Chcę wstrzymać wprowadzanie danych w skrypcie powłoki i poprosić użytkownika o dokonanie wyboru.
Średnia Yes, Nolub Canceltypu pytanie.
Jak to zrobić w typowym monicie bash?
Tak jak uwaga: konwencja dla monitów jest taka, że jeśli przedstawisz [yn]opcję, to, która jest pisana wielkimi literami, jest domyślna, tzn. [Yn]Domyślnie „tak” i [yN]domyślnie „nie”. Zobacz ux.stackexchange.com/a/40445/43532
Tyzoid
Każdy, kto przychodzi tutaj z ZSH, zapoznaj się z odpowiedzią na pytanie, jak używać readpolecenia, aby monitować
smac89,
Odpowiedzi:
1616
Najprostszą i najszerzej dostępną metodą uzyskiwania danych wejściowych od użytkownika w wierszu poleceń jest readpolecenie. Najlepszym sposobem zilustrowania tego zastosowania jest prosta demonstracja:
while true;do
read -p "Do you wish to install this program?" yn
case $yn in[Yy]*) make install;break;;[Nn]*) exit;;*) echo "Please answer yes or no.";;esacdone
echo "Do you wish to install this program?"
select yn in"Yes""No";docase $yn inYes) make install;break;;No) exit;;esacdone
Ze selectnie trzeba zdezynfekować wejście - wyświetla dostępne opcje i wpisać numer odpowiadający wyboru. Zapętla się również automatycznie, więc nie ma potrzeby, aby while truepętla próbowała się powtórzyć, jeśli dadzą nieprawidłowe dane wejściowe.
W swojej odpowiedzi Léa Gris pokazała sposób na agnostycyzm języka zapytań . Dostosowanie mojego pierwszego przykładu do lepszej obsługi wielu języków może wyglądać następująco:
set-- $(locale LC_MESSAGES)
yesptrn="$1"; noptrn="$2"; yesword="$3"; noword="$4"while true;do
read -p "Install (${yesword} / ${noword})? " yn
case $yn in
${yesptrn##^} ) make install; break;;
${noptrn##^} ) exit;;*) echo "Answer ${yesword} / ${noword}.";;esacdone
Oczywiście inne ciągi komunikacyjne pozostają tutaj nieprzetłumaczone (zainstaluj, odpowiedz), które należałoby rozwiązać w tłumaczeniu pełniejszym, ale w wielu przypadkach pomocne byłoby nawet tłumaczenie częściowe.
Korzystając z Bash w OS X Leopard, zmieniłem exitna, breakaby nie zamykać karty po wybraniu „nie”.
Trey Piepmeier,
1
Jak to działa z opcjami dłuższymi niż Tak lub Nie? W klauzuli przypadku, czy piszesz coś w stylu: Zainstaluj program i nic później nie rób) zainstaluj; złamać;
Shawn
1
@Shawn Korzystając z read , możesz oczywiście użyć dowolnego wzorca glob lub regex obsługiwanego przez instrukcję switch powłoki bash. Po prostu dopasowuje tekst wpisany do twoich wzorów, dopóki nie znajdzie pasującego tekstu. Za pomocą polecenia select lista opcji jest przekazywana do polecenia i wyświetla je użytkownikowi. Elementy na liście mogą być tak długie lub tak krótkie, jak chcesz. Polecam sprawdzenie ich stron podręcznika w celu uzyskania wyczerpujących informacji na temat użytkowania.
Myrddin Emrys
3
dlaczego jest breakw tym, selectjeśli nie ma pętli?
Jayen
1
@akostadinov Naprawdę powinienem więcej przeczytać historię edycji. Masz rację, mylę się i wprowadziłem błąd zgodnie z radą Jayana, hah. Błąd został później naprawiony, ale zmiany były tak daleko od siebie, że nawet nie pamiętałem, żeby to zmienić.
Myrddin Emrys
525
Co najmniej pięć odpowiedzi na jedno ogólne pytanie.
Zależy od
posix zgodny: może działać na słabych systemach z ogólnymi muszla środowiska
grzmotnąćspecyficzne: stosowanie tak zwanych baszizmów
a jeśli chcesz
proste pytanie / odpowiedź `` w linii '' (ogólne rozwiązania)
całkiem sformatowane interfejsy, jak ncurses lub bardziej graficzny za pomocą libgtk lub libqt ...
korzystaj z zaawansowanych możliwości historii odczytu
1. Ogólne rozwiązania POSIX
Możesz użyć readpolecenia, a następnie if ... then ... else:
echo -n "Is this a good question (y/n)? "
read answer
#/bin/sh
echo -n "Is this a good question (y/n)? "
old_stty_cfg=$(stty -g)
stty raw -echo
answer=$(while! head -c 1| grep -i '[ny]';do true ;done)
stty $old_stty_cfg
if echo "$answer"| grep -iq "^y";then
echo Yeselse
echo Nofi
Korzystanie z dedykowanych narzędzi
Istnieje wiele narzędzi, które zostały zbudowane za pomocą libncurses, libgtk, libqtlub innych bibliotek graficznych. Na przykład za pomocą whiptail:
if whiptail --yesno "Is this a good question"2060;then
echo Yeselse
echo Nofi
W zależności od systemu może być konieczne zastąpienie whiptailgo innym podobnym narzędziem:
dialog --yesno "Is this a good question"2060&& echo Yes
gdialog --yesno "Is this a good question"2060&& echo Yes
kdialog --yesno "Is this a good question"2060&& echo Yes
gdzie 20jest wysokość okna dialogowego w liczbie linii i 60szerokość okna dialogowego. Wszystkie te narzędzia mają prawie taką samą składnię.
read -p "Is this a good question (y/n)? " answer
case ${answer:0:1}in
y|Y )
echo Yes;;*)
echo No;;esac
Wolę używać, casewięc mogę nawet przetestować w yes | ja | si | ouirazie potrzeby ...
zgodnie z funkcją jednego klucza
W bash możemy określić długość zamierzonego wejścia dla readpolecenia:
read -n 1-p "Is this a good question (y/n)? " answer
W bash readpolecenie akceptuje parametr limitu czasu , który może być przydatny.
read -t 3-n 1-p "Is this a good question (y/n)? " answer
[-z "$answer"]&& answer="Yes"# if 'yes' have to be default choice
3. Kilka sztuczek dla dedykowanych narzędzi
Bardziej zaawansowane okna dialogowe poza prostymi yes - nocelami:
dialog --menu "Is this a good question"206012 y Yes n No m Maybe
Pasek postępu:
dialog --gauge "Filling the tank"20600<<(for i in{1..100};do
printf "XXX\n%d\n%(%a %b %T)T progress: %d\nXXX\n" $i -1 $i
sleep .033done)
Mała wersja demo:
#!/bin/shwhile true ;do[-x "$(which ${DIALOG%% *})"]|| DIALOG=dialog
DIALOG=$($DIALOG --menu "Which tool for next run?"2060122>&1 \
whiptail "dialog boxes from shell scripts">/dev/tty \
dialog "dialog boxes from shell with ncurses" \
gdialog "dialog boxes from shell with Gtk" \
kdialog "dialog boxes from shell with Kde")|| exit
clear;echo "Choosed: $DIALOG."for i in`seq 1 100`;do
date +"`printf "XXX\n%d\n%%a %%b %%T progress:%d\nXXX\n" $i $i`"
sleep .0125done| $DIALOG --gauge "Filling the tank"20600
$DIALOG --infobox "This is a simple info box\n\nNo action required"2060
sleep 3if $DIALOG --yesno "Do you like this demo?"2060;thenAnsYesNo=Yes;elseAnsYesNo=No;fiAnsInput=$($DIALOG --inputbox "A text:"2060"Text here..."2>&1>/dev/tty)AnsPass=$($DIALOG --passwordbox "A secret:"2060"First..."2>&1>/dev/tty)
$DIALOG --textbox /etc/motd 2060AnsCkLst=$($DIALOG --checklist "Check some..."206012 \
Correct"This demo is useful" off \
Fun"This demo is nice" off \
Strong"This demo is complex" on 2>&1>/dev/tty)AnsRadio=$($DIALOG --radiolist "I will:"206012 \
" -1""Downgrade this answer" off \
" 0""Not do anything" on \
" +1""Upgrade this anser" off 2>&1>/dev/tty)
out="Your answers:\nLike: $AnsYesNo\nInput: $AnsInput\nSecret: $AnsPass"
$DIALOG --msgbox "$out\nAttribs: $AnsCkLst\nNote: $AnsRadio"2060done
Zauważ, że sttyzapewnia -gmożliwość użycia: old_stty=$(stty -g); stty raw -echo; …; stty "$old_stty". To przywraca ustawienia dokładnie tak, jak zostały znalezione, które mogą, ale nie muszą być takie same jak stty -sane.
Jonathan Leffler,
3
read answerzinterpretuje odwrotne ukośniki przed spacjami i liniami, a w przeciwnym razie usuwa je, co rzadko jest zamierzone. Użyj read -r answerzamiast tego zgodnie z SC2162 .
vlfig
1
Metoda „Korzystanie z historii readline” jest tak strasznie nieodpowiednia dla pytania PO. Cieszę się, że i tak to uwzględniłeś. Mam dziesiątki znacznie bardziej skomplikowanych skryptów, które zamierzam zaktualizować za pomocą tego wzoru!
Bruno Bronosky,
5
Możesz używać casezarówno POSIX, jak i bash (użyj znaku zastępczego zamiast podciągu bash:) case $answer in; [Yy]* ) echo Yes ;;, ale wolę zamiast tego używać instrukcji warunkowej, faworyzując [ "$answer" != "${answer#[Yy]}" ]twoje echo "$answer" | grep -iq ^y. Jest bardziej przenośny (niektóre grepy spoza GNU nie implementują się -qpoprawnie) i nie ma wywołania systemowego. ${answer#[Yy]}używa rozszerzenia parametrów do usunięcia Ylub yod początku $answer, powodując nierówność, gdy którykolwiek z nich jest obecny. Działa to w dowolnej powłoce POSIX (dash, ksh, bash, zsh, busybox itp.).
Adam Katz
1
@CarterPape Tak, to był żart! Ale w tej oderwanej odpowiedzi możesz znaleźć wiele wskazówek (drugi punkt przedstawia co najmniej 3 różne metody)! I ... od około 5 lat po raz pierwszy opowiadasz o mojej metodzie liczenia! ;-))
F. Hauri
349
echo "Please enter some input: "
read input_variable
echo "You entered: $input_variable"
Nie zgadzam się, ponieważ implementuje tylko część funkcjonalności okna dialogowego „Tak, Nie, Anuluj” w DOS. Częścią, której nie implementuje, jest sprawdzanie wejścia ... zapętlanie do momentu otrzymania poprawnej odpowiedzi.
Myrddin Emrys
1
(Oryginalny tytuł pytania brzmiał: „Jak
poprosić
8
Ale oryginalny opis pytania pozostaje niezmieniony i zawsze pytany jest o odpowiedź na pytanie Tak / Nie / Anuluj. Tytuł został zaktualizowany, aby był jaśniejszy niż mój oryginalny, ale opis pytania był zawsze jasny (moim zdaniem).
Myrddin Emrys
165
Możesz użyć wbudowanego polecenia odczytu ; Użyj -popcji, aby zapytać użytkownika o pytanie.
Od wersji BASH4 możesz teraz -isugerować odpowiedź:
read -e -p "Enter the path to the file: "-i "/usr/local/etc/" FILEPATH
echo $FILEPATH
(Pamiętaj jednak, aby użyć opcji „readline”, -eaby umożliwić edycję linii za pomocą klawiszy strzałek)
Jeśli chcesz logiki „tak / nie”, możesz zrobić coś takiego:
read -e -p "
List the content of your home dir ? [Y/n] " YN
[[ $YN =="y"|| $YN =="Y"|| $YN ==""]]&& ls -la ~/
Należy zauważyć, że FILEPATHjest to nazwa zmiennej, którą wybrałeś i jest ustawiana wraz z odpowiedzią na wiersz polecenia. Więc jeśli miałbyś wtedy uruchomić vlc "$FILEPATH", na przykład vlcotworzyłby ten plik.
Ken Sharp
Jakie są korzyści z -edrugiego przykładu (proste tak / nie)?
JBallin,
Czy jest jakiś powód, aby użyć -e -pzamiast -ep?
JBallin,
1
Bez -eflagi / opcji możesz (w zależności od implementacji) nie być w stanie wpisać „y”, a następnie zmienić zdanie i zamienić na „n” (lub cokolwiek innego w tym zakresie); Podczas dokumentowania polecenia osobne wyszczególnienie opcji jest lepsze między innymi ze względu na czytelność / przejrzystość.
+1 Genialnie proste rozwiązanie. Jedyna rzecz: to podpowie, podpowie i podpowie ... dopóki nie dodasz exitwewnątrz :)
kaiser
5
(kaiser: Aby się od niego oderwać, wystarczy wpisać EOT:. Ctrl-DAle oczywiście prawdziwy kod, który go użyje, będzie wymagał przerwy lub wyjścia w ciele.)
Zorawar
12
Nie pozwoli to jednak na wpisanie y ani n. Możesz wybrać, wpisując 1 2 lub 3.
djjeck,
3
exitwyjdzie ze skryptu wszystkie razem, breakwyjdzie tylko z pętli, w której się znajdujesz (jeśli jesteś w pętli whilelub case)
wranvaud
57
read -p "Are you alright? (y/n) " RESP
if["$RESP"="y"];then
echo "Glad to hear it"else
echo "You need more bash programming"fi
Umieść cztery spacje na początku każdego wiersza, aby zachować formatowanie kodu.
Jouni K. Seppänen
10
Dlaczego podajemy „y” i „n” jako parametry do zapytania (), jeśli przełączniki wielkości liter są zakodowane na stałe? To tylko prośba o niewłaściwe użycie. Są to parametry stałe, niezmienne, więc echo w linii 2 powinno brzmieć: echo -n „$ 1 [T / N]?” Nie można ich zmienić, więc nie należy ich podawać.
Myrddin Emrys
1
@MyrddinEmrys Czy mógłbyś rozwinąć swój komentarz? Lub opublikuj link do artykułu lub kilku słów kluczowych, aby móc samodzielnie przeprowadzić badania.
Mateusz Piotrowski
4
@MateuszPiotrowski Odpowiedź została zredagowana i poprawiona od czasu mojego komentarza. Możesz kliknąć link „edytowany 23 grudnia” powyżej, aby wyświetlić wszystkie poprzednie wersje tej odpowiedzi. W 2008 roku kod był zupełnie inny.
Myrddin Emrys
27
Chcesz:
Wbudowane polecenia Bash (np. Przenośne)
Sprawdź TTY
Domyślna odpowiedź
Koniec czasu
Kolorowe pytanie
Skrawek
do_xxxx=y # In batch mode => Default is Yes[[-t 0]]&&# If TTY => Prompt the question
read -n 1-p $'\e[1;32m
Do xxxx? (Y/n)\e[0m ' do_xxxx # Store the answer in $do_xxxxif[[ $do_xxxx =~^(y|Y|)$ ]]# Do if 'y' or 'Y' or emptythen
xxxx
fi
@Jaw echo drukuje nowy wiersz po Twojej odpowiedzi. Bez tego następna rzecz do wydrukowania pojawi się natychmiast po Twojej odpowiedzi w tym samym wierszu. Spróbuj usunąć echona własne oczy.
Dennis
13
Aby uzyskać ładne pole tekstowe podobne do ncurses, skorzystaj z okna dialogowego poleceń takiego:
#!/bin/bashif(dialog --title "Message"--yesno "Want to do something risky?"625)# message box will have the size 25x6 charactersthen
echo "Let's do something risky"# do something riskyelse
echo "Let's stay boring"fi
Pakiet dialogowy jest instalowany domyślnie przynajmniej w systemie SUSE Linux. Wygląda jak:
yap, -e-inie pracuj w sh (powłoka Bourne'a), ale pytanie jest oznaczone bash konkretnie ..
Jahid
12
Możesz użyć wartości domyślnej REPLYna a read, przekonwertować na małe litery i porównać z zestawem zmiennych z wyrażeniem.
Skrypt obsługuje również ja/ si/oui
read -rp "Do you want a demo? [y/n/c] "[[ ${REPLY,,}=~^(c|cancel)$ ]]&&{ echo "Selected Cancel"; exit 1;}if[[ ${REPLY,,}=~^(y|yes|j|ja|s|si|o|oui)$ ]];then
echo "Positive"fi
W powłoce POSIX można obsługiwać rozpoznawanie ustawień narodowych „Tak / Nie wybór”; za pomocą wpisów z LC_MESSAGESkategorii ustawień regionalnych czarownica zapewnia gotowe wzorce RegEx pasujące do danych wejściowych oraz ciągi znaków dla zlokalizowanego Tak Nie.
#!/usr/bin/env sh# Getting LC_MESSAGES values into variables# shellcheck disable=SC2046 # Intended IFS splitting
IFS='
'set-- $(locale LC_MESSAGES)
yesexpr="$1"
noexpr="$2"
yesstr="$3"
nostr="$4"
messages_codeset="$5"# unused here, but kept as documentation# Display Yes / No ? prompt into locale
echo "$yesstr / $nostr ?"# Read answer
read -r yn
# Test answercase"$yn"in# match only work with the character class from the expression
${yesexpr##^}) echo "answer $yesstr" ;;
${noexpr##^}) echo "answer $nostr" ;;esac
yesstrI nostrlocale słowa kluczowe a YESSTRi NOSTRlanginfo przedmioty były dawniej stosowane do użytkowników mecz pozytywnych i negatywnych odpowiedzi. W POSIX.1-2008 Z yesexpr, noexpr, YESEXPR, i NOEXPRrozszerzone wyrażenia regularne zastąpiły je. Aplikacje powinny korzystać z ogólnych funkcji przesyłania wiadomości opartych na ustawieniach regionalnych, aby wydawać komunikaty monitujące, które zawierają przykładowe pożądane odpowiedzi.
Alternatywnie, używając ustawień narodowych w Bash:
Uwielbiam dodanie opcji agnostycznej języka. Dobra robota.
Myrddin Emrys
1
Niestety POSIX określa tylko dwa pierwsze (yesexpr i noexpr). Na Ubuntu 16, takstr i nostr są puste.
Urhixidur
1
Ale poczekaj! Są gorsze wiadomości! Wyrażenia instrukcji bash nie są regularne, są wyrażeniami nazw plików. Tak więc yesexpr i noexpr w Ubuntu 16 (odpowiednio „^ [yY]. *” I „^ [nN]. *”) Całkowicie się nie powiodą z powodu osadzonego okresu. W wyrażeniu regularnym „. *” Oznacza „dowolny znak inny niż znak, zero lub więcej razy”. Ale w opisie przypadku jest to dosłowne „”. po którym następuje dowolna liczba znaków.
Urhixidur
1
Ostatecznie najlepszym, co można zrobić z yesexpri noexprw środowisku powłoki, jest wykorzystanie go w bash za specyficzny RegEx dopasowywaniaif [[ "$yn" =~ $yesexpr ]]; then echo $"Answered yes"; else echo $"Answered no"; fi
Léa Gris
10
Tylko jedno naciśnięcie klawisza
Oto dłuższe, ale wielokrotnego użytku i modułowe podejście:
Zwraca 0= tak i 1= nie
Nie trzeba naciskać Enter - tylko jeden znak
Można nacisnąć, enteraby zaakceptować domyślny wybór
Może wyłączyć domyślny wybór, aby wymusić wybór
Działa zarówno dla, jak zshi dla bash.
Domyślnie „nie” po naciśnięciu Enter
Zauważ, że Njest on kapitałowany. Tutaj naciśnij klawisz Enter, przyjmując wartość domyślną:
Powyżej po prostu nacisnąłem Enter, więc polecenie zostało uruchomione.
Brak domyślnego włączenia enter- wymaga ylubn
$ get_yes_keypress "Here you cannot press enter. Do you like this [y/n]? "
Here you cannot press enter. Do you like this [y/n]? k
Here you cannot press enter. Do you like this [y/n]?
Here you cannot press enter. Do you like this [y/n]? n
$ echo $?
1
Tutaj 1lub false został zwrócony. Zauważ, że dzięki tej funkcji niższego poziomu musisz podać swój własny [y/n]?monit.
Kod
# Read a single char from /dev/tty, prompting with "$*"# Note: pressing enter will return a null string. Perhaps a version terminated with X and then remove it in caller?# See https://unix.stackexchange.com/a/367880/143394 for dealing with multi-byte, etc.function get_keypress {local REPLY IFS=>/dev/tty printf '%s'"$*"[[ $ZSH_VERSION ]]&& read -rk1 # Use -u0 to read from STDIN# See https://unix.stackexchange.com/q/383197/143394 regarding '\n' -> ''[[ $BASH_VERSION ]]&&</dev/tty read -rn1
printf '%s'"$REPLY"}# Get a y/n from the user, return yes=0, no=1 enter=$2# Prompt using $1.# If set, return $2 on pressing enter, useful for cancel or defualtingfunction get_yes_keypress {local prompt="${1:-Are you sure [y/n]? }"local enter_return=$2
local REPLY
# [[ ! $prompt ]] && prompt="[y/n]? "while REPLY=$(get_keypress "$prompt");do[[ $REPLY ]]&& printf '\n'# $REPLY blank if user presses entercase"$REPLY"in
Y|y)return0;;
N|n)return1;;'')[[ $enter_return ]]&&return"$enter_return"esacdone}# Credit: http://unix.stackexchange.com/a/14444/143394# Prompt to confirm, defaulting to NO on <enter># Usage: confirm "Dangerous. Are you sure?" && rm *function confirm {local prompt="${*:-Are you sure} [y/N]? "
get_yes_keypress "$prompt"1}# Prompt to confirm, defaulting to YES on <enter>function confirm_yes {local prompt="${*:-Are you sure} [Y/n]? "
get_yes_keypress "$prompt"0}
Kiedy przetestowałem ten skrypt, zamiast outut powyżej, dostałem Show dangerous command [y/N]? [y/n]?iShow dangerous command [Y/n]? [y/n]?
Ilias Karim
Dzięki @IliasKarim, naprawiłem to właśnie teraz.
Tom Hale
9
Przepraszamy za zamieszczanie postów na tak starym postu. Kilka tygodni temu miałem do czynienia z podobnym problemem, w moim przypadku potrzebowałem rozwiązania, które działałoby również w internetowym skrypcie instalacyjnym, np .:curl -Ss https://raw.github.com/_____/installer.sh | bash
Używanie read yesno < /dev/ttydziała dobrze dla mnie:
echo -n "These files will be uploaded. Is this ok? (y/n) "
read yesno </dev/tty
if["x$yesno"="xy"];then# Yeselse# Nofi
Ważną częścią tego jest sprawdzanie poprawności danych wejściowych. Myślę, że dostosowanie mojego pierwszego przykładu do akceptowania ttydanych wejściowych, tak jak zrobiłbyś to samo, zrobiłoby to również dla ciebie, a także dostało się zapętlenia na złych danych wejściowych (wyobraź sobie kilka znaków w buforze; twoja metoda zmusiłaby użytkownika, aby zawsze wybierał nie).
Myrddin Emrys
7
Zauważyłem, że nikt nie opublikował odpowiedzi pokazującej wielowierszowe menu echa dla tak prostego wprowadzania danych przez użytkownika, więc oto mój wybór:
Jednym prostym sposobem na to jest za pomocą xargs -plub GNUparallel --interactive .
Podoba mi się w tym nieco bardziej zachowanie xargs, ponieważ wykonuje on każde polecenie natychmiast po znaku zachęty, podobnie jak inne interaktywne polecenia unix, zamiast zbierać tak, aby uruchomić je na końcu. (Możesz Ctrl-C po przejściu przez te, które chciałeś.)
Nieźle, ale xargs --interactiveogranicza się do tak lub nie. Dopóki to wszystko, czego potrzebujesz, może wystarczyć, ale moje pierwotne pytanie zawierało przykład z trzema możliwymi wynikami. Naprawdę podoba mi się, że można go przesyłać strumieniowo; wiele typowych scenariuszy zyskałoby na tym, że można go potokować.
Myrddin Emrys
Widzę. Myślałem, że „anuluj” miało po prostu zatrzymać wszelkie dalsze wykonywanie, które obsługuje to za pomocą Ctrl-C, ale jeśli musisz zrobić coś bardziej złożonego po anulowaniu (lub nie), to nie wystarczy.
Joshua Goldberg,
3
Jako przyjaciel polecenia jednowierszowego użyłem:
Czy możesz wyjaśnić użycie zmiennej pytania? Wygląda mi na to, że został wyczyszczony po jednej wkładce, więc jak używasz tej linii do ZROBIENIA czegokolwiek?
Myrddin Emrys
monit zostanie wyczyszczony po pętli while. Ponieważ chcę później zainicjować zmienną zachęty (ponieważ częściej używam instrukcji). Umieszczenie tego wiersza w skrypcie powłoki będzie kontynuowane tylko wtedy, gdy zostanie wpisane y | Y i wyjdzie, jeśli zostanie wpisane n | N, lub powtórzy zapytanie o dane wejściowe dla całej reszty.
ccDict
3
Użyłem tego casestwierdzenia kilka razy w takim scenariuszu, użycie statystyki przypadku jest dobrym sposobem na obejście tego. whilePętla, że ecapsulates ten caseblok, który wykorzystuje stan logiczny mogą być realizowane w celu przeprowadzenia jeszcze większą kontrolę programu i spełniać wiele innych wymagań. Po spełnieniu wszystkich warunków breakmożna użyć przycisku, który przekaże kontrolę z powrotem do głównej części programu. Ponadto, aby spełnić inne warunki, można oczywiście dodać instrukcje warunkowe, które towarzyszą strukturom kontrolnym: caseinstrukcja i możliwewhile pętla.
Przykład użycia caseinstrukcji w celu spełnienia żądania
#! /bin/sh # For potential users of BSD, or other systems who do not# have a bash binary located in /bin the script will be directed to# a bourne-shell, e.g. /bin/sh# NOTE: It would seem best for handling user entry errors or# exceptions, to put the decision required by the input # of the prompt in a case statement (case control structure),
echo Would you like us to perform the option:"(Y|N)"
read inPut
case $inPut in# echoing a command encapsulated by # backticks (``) executes the command"Y") echo `Do something crazy`;;# depending on the scenario, execute the other option# or leave as default"N") echo `execute another option`;;esac
exit
Wydaje się to złożone i kruche. Jak o właśnieyn(){ read -s -n 1 -p '[y/n]'; test "$REPLY" = "y" ; } yn && echo success || echo failure
tripleee
2
W odpowiedzi na inne:
Nie musisz określać wielkości liter w BASH4, po prostu użyj „,,”, aby małe litery były zmienne. Również zdecydowanie nie lubię umieszczać kodu w bloku odczytu, uzyskiwać wynik i radzić sobie z nim poza blokiem odczytu IMO. Dołącz także „q”, aby wyjść z IMO. Na koniec, dlaczego wpisz „tak”, po prostu użyj -n1 i naciśnij klawisz y.
Przykład: użytkownik może nacisnąć t / n, a także q, aby wyjść.
ans=''while true;do
read -p "So is MikeQ the greatest or what (y/n/q) ?"-n1 ans
case ${ans,,}in
y|n|q)break;;*) echo "Answer y for yes / n for no or q for quit.";;esacdone
echo -e "\nAnswer = $ans"if[["${ans,,}"=="q"]];then
echo "OK Quitting, we will assume that he is"
exit 0fiif[["${ans,,}"=="y"]];then
echo "MikeQ is the greatest!!"else
echo "No? MikeQ is not the greatest?"fi
W większości przypadków w takich sytuacjach konieczne jest kontynuowanie wykonywania skryptu, dopóki użytkownik nie wprowadzi „tak”, a zatrzymanie nastąpi tylko wtedy, gdy użytkownik wprowadzi „nie”. Poniższy fragment pomoże Ci to osiągnąć!
#!/bin/bash
input="yes"while["$input"=="yes"]do
echo "execute script functionality here..!!"
echo "Do you want to continue (yes/no)?"
read input
done
[yn]
opcję, to, która jest pisana wielkimi literami, jest domyślna, tzn.[Yn]
Domyślnie „tak” i[yN]
domyślnie „nie”. Zobacz ux.stackexchange.com/a/40445/43532read
polecenia, aby monitowaćOdpowiedzi:
Najprostszą i najszerzej dostępną metodą uzyskiwania danych wejściowych od użytkownika w wierszu poleceń jest
read
polecenie. Najlepszym sposobem zilustrowania tego zastosowania jest prosta demonstracja:Inną metodą, zauważył przez Stevena Huwig , bash za
select
polecenie. Oto ten sam przykład, używającselect
:Ze
select
nie trzeba zdezynfekować wejście - wyświetla dostępne opcje i wpisać numer odpowiadający wyboru. Zapętla się również automatycznie, więc nie ma potrzeby, abywhile true
pętla próbowała się powtórzyć, jeśli dadzą nieprawidłowe dane wejściowe.W swojej odpowiedzi Léa Gris pokazała sposób na agnostycyzm języka zapytań . Dostosowanie mojego pierwszego przykładu do lepszej obsługi wielu języków może wyglądać następująco:
Oczywiście inne ciągi komunikacyjne pozostają tutaj nieprzetłumaczone (zainstaluj, odpowiedz), które należałoby rozwiązać w tłumaczeniu pełniejszym, ale w wielu przypadkach pomocne byłoby nawet tłumaczenie częściowe.
Wreszcie, należy zapoznać się z doskonałą odpowiedź przez F. HAURI .
źródło
exit
na,break
aby nie zamykać karty po wybraniu „nie”.break
w tym,select
jeśli nie ma pętli?Co najmniej pięć odpowiedzi na jedno ogólne pytanie.
Zależy od
a jeśli chcesz
1. Ogólne rozwiązania POSIX
Możesz użyć
read
polecenia, a następnieif ... then ... else
:(Dzięki komentarzowi Adama Katza : zastąpiłem powyższy test testem, który jest bardziej przenośny i unika jednego widelca :)
POSIX, ale funkcja jednego klucza
Ale jeśli nie chcesz, aby użytkownik musiał trafić Return, możesz napisać:
( Edytowano: Jak słusznie sugerują @JathanathanLeffler, zapisanie konfiguracji stty może być lepsze niż po prostu zmusić ich do rozsądku .)
Uwaga: zostało to przetestowane podsh, grzmotnąć, ksh, dziarskość i busybox!
To samo, ale czekając wprost na ylub n:
Korzystanie z dedykowanych narzędzi
Istnieje wiele narzędzi, które zostały zbudowane za pomocą
libncurses
,libgtk
,libqt
lub innych bibliotek graficznych. Na przykład za pomocąwhiptail
:W zależności od systemu może być konieczne zastąpienie
whiptail
go innym podobnym narzędziem:gdzie
20
jest wysokość okna dialogowego w liczbie linii i60
szerokość okna dialogowego. Wszystkie te narzędzia mają prawie taką samą składnię.2. Rozwiązania specyficzne dla Bash
Podstawowa metoda liniowa
Wolę używać,
case
więc mogę nawet przetestować wyes | ja | si | oui
razie potrzeby ...zgodnie z funkcją jednego klucza
W bash możemy określić długość zamierzonego wejścia dla
read
polecenia:W bash
read
polecenie akceptuje parametr limitu czasu , który może być przydatny.3. Kilka sztuczek dla dedykowanych narzędzi
Bardziej zaawansowane okna dialogowe poza prostymi
yes - no
celami:Pasek postępu:
Mała wersja demo:
Więcej próbek? Zobacz Korzystanie z whiptail do wybierania urządzenia USB i wymiennego selektora pamięci USB: USBKeyChooser
5. Korzystanie z historii readline
Przykład:
Spowoduje to utworzenie pliku
.myscript.history
w$HOME
katalogu, niż można użyć polecenia readline historii, na przykład Up, Down, Ctrl+ ri innych.źródło
stty
zapewnia-g
możliwość użycia:old_stty=$(stty -g); stty raw -echo; …; stty "$old_stty"
. To przywraca ustawienia dokładnie tak, jak zostały znalezione, które mogą, ale nie muszą być takie same jakstty -sane
.read answer
zinterpretuje odwrotne ukośniki przed spacjami i liniami, a w przeciwnym razie usuwa je, co rzadko jest zamierzone. Użyjread -r answer
zamiast tego zgodnie z SC2162 .case
zarówno POSIX, jak i bash (użyj znaku zastępczego zamiast podciągu bash:)case $answer in; [Yy]* ) echo Yes ;;
, ale wolę zamiast tego używać instrukcji warunkowej, faworyzując[ "$answer" != "${answer#[Yy]}" ]
twojeecho "$answer" | grep -iq ^y
. Jest bardziej przenośny (niektóre grepy spoza GNU nie implementują się-q
poprawnie) i nie ma wywołania systemowego.${answer#[Yy]}
używa rozszerzenia parametrów do usunięciaY
luby
od początku$answer
, powodując nierówność, gdy którykolwiek z nich jest obecny. Działa to w dowolnej powłoce POSIX (dash, ksh, bash, zsh, busybox itp.).źródło
Możesz użyć wbudowanego polecenia odczytu ; Użyj
-p
opcji, aby zapytać użytkownika o pytanie.Od wersji BASH4 możesz teraz
-i
sugerować odpowiedź:(Pamiętaj jednak, aby użyć opcji „readline”,
-e
aby umożliwić edycję linii za pomocą klawiszy strzałek)Jeśli chcesz logiki „tak / nie”, możesz zrobić coś takiego:
źródło
FILEPATH
jest to nazwa zmiennej, którą wybrałeś i jest ustawiana wraz z odpowiedzią na wiersz polecenia. Więc jeśli miałbyś wtedy uruchomićvlc "$FILEPATH"
, na przykładvlc
otworzyłby ten plik.-e
drugiego przykładu (proste tak / nie)?-e -p
zamiast-ep
?-e
flagi / opcji możesz (w zależności od implementacji) nie być w stanie wpisać „y”, a następnie zmienić zdanie i zamienić na „n” (lub cokolwiek innego w tym zakresie); Podczas dokumentowania polecenia osobne wyszczególnienie opcji jest lepsze między innymi ze względu na czytelność / przejrzystość.Bash wybrał do tego celu.
źródło
exit
wewnątrz :)Ctrl-D
Ale oczywiście prawdziwy kod, który go użyje, będzie wymagał przerwy lub wyjścia w ciele.)exit
wyjdzie ze skryptu wszystkie razem,break
wyjdzie tylko z pętli, w której się znajdujesz (jeśli jesteś w pętliwhile
lubcase
)źródło
Oto coś, co złożyłem:
Jestem początkującym, więc weź to z odrobiną soli, ale wydaje się, że działa.
źródło
case $yn in
nacase ${yn:-$2} in
, możesz użyć drugiego argumentu jako wartości domyślnej, Y lub N.case $yn
nacase "${yn:-Y}"
domyślną takźródło
Chcesz:
Skrawek
Objaśnienia
[[ -t 0 ]] && read ...
=> Polecenie wywołania,read
jeśli TTYread -n 1
=> Poczekaj na jeden znak$'\e[1;32m ... \e[0m '
=> Drukuj na zielono(zielony jest w porządku, ponieważ można go odczytać zarówno na białym / czarnym tle)
[[ $do_xxxx =~ ^(y|Y|)$ ]]
=> wyrażenie regularne bashLimit czasu => Domyślna odpowiedź to Nie
źródło
Najłatwiejszym sposobem osiągnięcia tego celu przy użyciu najmniejszej liczby linii jest:
To
if
tylko przykład: od Ciebie zależy, jak obsłużyć tę zmienną.źródło
Użyj
read
polecenia:a potem wszystkie inne potrzebne rzeczy
źródło
To rozwiązanie odczytuje pojedynczy znak i wywołuje funkcję w odpowiedzi TAK.
źródło
echo
na własne oczy.Aby uzyskać ładne pole tekstowe podobne do ncurses, skorzystaj z okna dialogowego poleceń takiego:
Pakiet dialogowy jest instalowany domyślnie przynajmniej w systemie SUSE Linux. Wygląda jak:
źródło
-e
Opcja pozwala użytkownikowi na edycję wejście przy użyciu klawiszy strzałek.Jeśli chcesz użyć sugestii jako danych wejściowych:
-i
opcja wypisuje sugestywne dane wejściowe.źródło
-e
-i
nie pracuj w sh (powłoka Bourne'a), ale pytanie jest oznaczone bash konkretnie ..Możesz użyć wartości domyślnej
REPLY
na aread
, przekonwertować na małe litery i porównać z zestawem zmiennych z wyrażeniem.Skrypt obsługuje również
ja
/si
/oui
źródło
W powłoce POSIX można obsługiwać rozpoznawanie ustawień narodowych „Tak / Nie wybór”; za pomocą wpisów z
LC_MESSAGES
kategorii ustawień regionalnych czarownica zapewnia gotowe wzorce RegEx pasujące do danych wejściowych oraz ciągi znaków dla zlokalizowanego Tak Nie.EDYCJA: Jak wspomniał @Urhixidur w swoim komentarzu :
Zobacz: https://www.ee.ryerson.ca/~courses/ele709/susv4/xrat/V4_xbd_chap07.html#tag_21_07_03_06
Alternatywnie, używając ustawień narodowych w Bash:
Odpowiedź jest dopasowywana za pomocą wyrażeń regularnych dostarczonych przez środowisko regionalne.
Aby przetłumaczyć pozostałe komunikaty, użyj,
bash --dump-po-strings scriptname
aby wyprowadzić ciągi znaków do lokalizacji:źródło
yesexpr
inoexpr
w środowisku powłoki, jest wykorzystanie go w bash za specyficzny RegEx dopasowywaniaif [[ "$yn" =~ $yesexpr ]]; then echo $"Answered yes"; else echo $"Answered no"; fi
Tylko jedno naciśnięcie klawisza
Oto dłuższe, ale wielokrotnego użytku i modułowe podejście:
0
= tak i1
= niezsh
i dlabash
.Domyślnie „nie” po naciśnięciu Enter
Zauważ, że
N
jest on kapitałowany. Tutaj naciśnij klawisz Enter, przyjmując wartość domyślną:Pamiętaj też, że
[y/N]?
został on automatycznie dołączony. Domyślne „nie” jest akceptowane, więc nic nie jest powtarzane.Powtórz monit, dopóki nie zostanie udzielona poprawna odpowiedź:
Domyślnie „tak” po naciśnięciu Enter
Pamiętaj, że
Y
wielkie litery:Powyżej po prostu nacisnąłem Enter, więc polecenie zostało uruchomione.
Brak domyślnego włączenia enter- wymaga
y
lubn
Tutaj
1
lub false został zwrócony. Zauważ, że dzięki tej funkcji niższego poziomu musisz podać swój własny[y/n]?
monit.Kod
źródło
Show dangerous command [y/N]? [y/n]?
iShow dangerous command [Y/n]? [y/n]?
Przepraszamy za zamieszczanie postów na tak starym postu. Kilka tygodni temu miałem do czynienia z podobnym problemem, w moim przypadku potrzebowałem rozwiązania, które działałoby również w internetowym skrypcie instalacyjnym, np .:
curl -Ss https://raw.github.com/_____/installer.sh | bash
Używanie
read yesno < /dev/tty
działa dobrze dla mnie:Mam nadzieję, że to komuś pomoże.
źródło
tty
danych wejściowych, tak jak zrobiłbyś to samo, zrobiłoby to również dla ciebie, a także dostało się zapętlenia na złych danych wejściowych (wyobraź sobie kilka znaków w buforze; twoja metoda zmusiłaby użytkownika, aby zawsze wybierał nie).Zauważyłem, że nikt nie opublikował odpowiedzi pokazującej wielowierszowe menu echa dla tak prostego wprowadzania danych przez użytkownika, więc oto mój wybór:
Ta metoda została opublikowana w nadziei, że ktoś może uznać ją za przydatną i oszczędzającą czas.
źródło
Wersja wielokrotnego wyboru:
Przykład:
Ustawi się
REPLY
nay
(wewnątrz skryptu).źródło
Sugeruję skorzystanie z okna dialogowego ...
jest prosty i łatwy w użyciu, istnieje również wersja gnome o nazwie gdialog, która przyjmuje dokładnie te same parametry, ale pokazuje styl GUI na X.
źródło
Zainspirowany odpowiedziami @Mark i @Myrddin stworzyłem tę funkcję dla uniwersalnego monitu
użyj tego w ten sposób:
źródło
bardziej ogólne byłoby:
źródło
Jednym prostym sposobem na to jest za pomocą
xargs -p
lub GNUparallel --interactive
.Podoba mi się w tym nieco bardziej zachowanie xargs, ponieważ wykonuje on każde polecenie natychmiast po znaku zachęty, podobnie jak inne interaktywne polecenia unix, zamiast zbierać tak, aby uruchomić je na końcu. (Możesz Ctrl-C po przejściu przez te, które chciałeś.)
na przykład,
źródło
xargs --interactive
ogranicza się do tak lub nie. Dopóki to wszystko, czego potrzebujesz, może wystarczyć, ale moje pierwotne pytanie zawierało przykład z trzema możliwymi wynikami. Naprawdę podoba mi się, że można go przesyłać strumieniowo; wiele typowych scenariuszy zyskałoby na tym, że można go potokować.Jako przyjaciel polecenia jednowierszowego użyłem:
Napisane długie, działa w następujący sposób:
źródło
Użyłem tego
case
stwierdzenia kilka razy w takim scenariuszu, użycie statystyki przypadku jest dobrym sposobem na obejście tego.while
Pętla, że ecapsulates tencase
blok, który wykorzystuje stan logiczny mogą być realizowane w celu przeprowadzenia jeszcze większą kontrolę programu i spełniać wiele innych wymagań. Po spełnieniu wszystkich warunkówbreak
można użyć przycisku, który przekaże kontrolę z powrotem do głównej części programu. Ponadto, aby spełnić inne warunki, można oczywiście dodać instrukcje warunkowe, które towarzyszą strukturom kontrolnym:case
instrukcja i możliwewhile
pętla.Przykład użycia
case
instrukcji w celu spełnienia żądaniaźródło
Tak / Nie / Anuluj
Funkcjonować
Stosowanie
Potwierdź, wprowadzając czyste dane użytkownika
Funkcjonować
Stosowanie
źródło
źródło
yn(){ read -s -n 1 -p '[y/n]'; test "$REPLY" = "y" ; } yn && echo success || echo failure
W odpowiedzi na inne:
Nie musisz określać wielkości liter w BASH4, po prostu użyj „,,”, aby małe litery były zmienne. Również zdecydowanie nie lubię umieszczać kodu w bloku odczytu, uzyskiwać wynik i radzić sobie z nim poza blokiem odczytu IMO. Dołącz także „q”, aby wyjść z IMO. Na koniec, dlaczego wpisz „tak”, po prostu użyj -n1 i naciśnij klawisz y.
Przykład: użytkownik może nacisnąć t / n, a także q, aby wyjść.
źródło
W większości przypadków w takich sytuacjach konieczne jest kontynuowanie wykonywania skryptu, dopóki użytkownik nie wprowadzi „tak”, a zatrzymanie nastąpi tylko wtedy, gdy użytkownik wprowadzi „nie”. Poniższy fragment pomoże Ci to osiągnąć!
źródło