W Bash, jak dodać „Czy na pewno [T / n]” do dowolnego polecenia lub aliasu?


228

W tym konkretnym przypadku chciałbym dodać potwierdzenie w Bash dla

Jesteś pewny? [T / n]

dla Mercurial's hg push ssh://username@www.example.com//somepath/morepath, który jest właściwie pseudonimem. Czy istnieje standardowe polecenie, które można dodać do aliasu, aby to osiągnąć?

Powodem jest to hg pushi hg outmoże brzmieć podobnie, a czasami, kiedy chcę hgoutrepo, mogę przypadkowo pisać hgpushrepo(oba są pseudonimami).

Aktualizacja: jeśli może to być coś w rodzaju wbudowanego polecenia z innym poleceniem, takim jak: confirm && hg push ssh://...byłoby świetnie ... tylko polecenie, które może poprosić o a yeslub nokontynuować resztę, jeśli yes.


1
Prawdopodobnie będziesz chciał użyć funkcji zamiast aliasu. From info bash: „W prawie każdym celu funkcje powłoki są lepsze niż aliasy”.
Wstrzymano do odwołania.

naprawdę? nawet dla takich jak ls -llub rm -i?
nonpolarity

5
Dla prawie każdego, nie każdego . Nawiasem mówiąc, nigdy nie rób czegoś takiego alias rm='rm -i'. Pewnego dnia, gdy będziesz go najbardziej potrzebować, nie będzie tam aliasu i boom!coś ważnego zostanie utracone.
Wstrzymano do odwołania.

poczekaj, jeśli nie masz aliasu rm -i, nie możesz liczyć na skrypt powłoki. Więc zawsze piszesz za rm -ikażdym razem?
nonpolarity

8
Chodzi o nawyki . Możesz stworzyć alias taki jak ten w moim poprzednim komentarzu i mieć nawyk pisania rmi oczekiwania na -izachowanie, wtedy pewnego dnia aliasu nie ma (z jakiegoś powodu jest on rozbrojony lub nie jest ustawiony lub jesteś w innym systemie ) i piszesz, rma następnie natychmiast usuwa rzeczy bez potwierdzenia. Ups! Jeśli jednak użyjesz aliasu takiego jak alias askrm='rm -i'wtedy, wszystko będzie w porządku, ponieważ pojawi się błąd „nie znaleziono polecenia”.
Wstrzymano do odwołania.

Odpowiedzi:


332

Są to bardziej kompaktowe i wszechstronne formy Hamisha odpowiedź . Obsługują dowolną kombinację wielkich i małych liter:

read -r -p "Are you sure? [y/N] " response
case "$response" in
    [yY][eE][sS]|[yY]) 
        do_something
        ;;
    *)
        do_something_else
        ;;
esac

Lub, dla Bash> = wersja 3.2:

read -r -p "Are you sure? [y/N] " response
if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]
then
    do_something
else
    do_something_else
fi

Uwaga: Jeśli $responsejest pusty ciąg, spowoduje błąd. Aby to naprawić, wystarczy dodać cudzysłów: "$response". - Zawsze używaj podwójnych cudzysłowów w zmiennych zawierających ciągi znaków (np .: wolisz używać "$@"zamiast tego $@).

Lub Bash 4.x:

read -r -p "Are you sure? [y/N] " response
response=${response,,}    # tolower
if [[ "$response" =~ ^(yes|y)$ ]]
...

Edytować:

W odpowiedzi na twoją edycję, oto jak stworzysz i użyjesz confirmpolecenia opartego na pierwszej wersji w mojej odpowiedzi (działałoby podobnie z pozostałymi dwoma):

confirm() {
    # call with a prompt string or use a default
    read -r -p "${1:-Are you sure? [y/N]} " response
    case "$response" in
        [yY][eE][sS]|[yY]) 
            true
            ;;
        *)
            false
            ;;
    esac
}

Aby użyć tej funkcji:

confirm && hg push ssh://..

lub

confirm "Would you really like to do a push?" && hg push ssh://..

9
Właściwie powinno to być [t / N], a nie [T / n] dla bieżącego testu.
Simon A. Eugster,

Warto wspomnieć, że jeśli chcesz sprawdzić not equal todrugi przykład, powinieneś rzucić $responsezmienną. Np if [[ ! $response =~ ^([yY][eE][sS]|[yY])$ ]]. :
João Cunha

@ JoãoCunha: Byłoby to „niepasujące”, a nie „nierównane”, ponieważ =~jest operatorem dopasowania wyrażenia regularnego.
Wstrzymano do odwołania.

@DennisWilliamson ma rację, właśnie to chciałem powiedzieć. Z jakiegoś powodu nie mogę edytować mojego komentarza.
João Cunha

6
Ładna funkcja ogólnego przeznaczenia tak / nie . obsługuje silny znak zachęty i opcjonalnie ustawienie domyślnej wartości „y” lub „n”.
wkw

19

Oto z grubsza fragment, który chcesz. Pozwól mi dowiedzieć się, jak przekazać argumenty.

read -p "Are you sure you want to continue? <y/N> " prompt
if [[ $prompt == "y" || $prompt == "Y" || $prompt == "yes" || $prompt == "Yes" ]]
then
  # http://stackoverflow.com/questions/1537673/how-do-i-forward-parameters-to-other-command-in-bash-script
else
  exit 0
fi

Uważaj na yes | command name here:)


13

Potwierdzenia można łatwo ominąć przy zwrotach karetki i uważam, że warto stale pytać o prawidłowe dane wejściowe.

Oto funkcja ułatwiająca to. „nieprawidłowe wejście” pojawia się na czerwono, jeśli Y | N nie zostanie odebrane, a użytkownik zostanie ponownie zapytany.

prompt_confirm() {
  while true; do
    read -r -n 1 -p "${1:-Continue?} [y/n]: " REPLY
    case $REPLY in
      [yY]) echo ; return 0 ;;
      [nN]) echo ; return 1 ;;
      *) printf " \033[31m %s \n\033[0m" "invalid input"
    esac 
  done  
}

# example usage
prompt_confirm "Overwrite File?" || exit 0

Możesz zmienić domyślny monit, przekazując argument


12

Aby uniknąć jawnego sprawdzania tych wariantów „tak”, można użyć operatora wyrażeń regularnych bash „= ~” z wyrażeniem regularnym:

read -p "Are you sure you want to continue? <y/N> " prompt
if [[ $prompt =~ [yY](es)* ]]
then
(etc...)

To sprawdza, czy dane wejściowe użytkownika zaczynają się od „y” czy „Y”, po których następuje zero lub więcej „es”.


5

Może to być hack:

jak w pytaniu W Unix / Bash, czy „xargs -p” jest dobrym sposobem na monitowanie o potwierdzenie przed uruchomieniem jakiegokolwiek polecenia?

możemy użyć xargsdo wykonania pracy:

echo ssh://username@www.example.com//somepath/morepath | xargs -p hg push

oczywiście będzie to ustawione jako alias hgpushrepo

Przykład:

$ echo foo | xargs -p ls -l
ls -l foo?...y
-rw-r--r--  1 mikelee    staff  0 Nov 23 10:38 foo

$ echo foo | xargs -p ls -l
ls -l foo?...n

$

4

Dodaj następujące elementy do pliku / etc / bashrc. Ten skrypt dodaje rezydentną „funkcję” zamiast aliasu zwanego „potwierdzeniem”.


function confirm( )
{
#alert the user what they are about to do.
echo "About to $@....";
#confirm with the user
read -r -p "Are you sure? [Y/n]" response
case "$response" in
    [yY][eE][sS]|[yY]) 
              #if yes, then execute the passed parameters
               "$@"
               ;;
    *)
              #Otherwise exit...
              echo "ciao..."
              exit
              ;;
esac
}

Miły. Jednak kilka drobnych poprawek: powinieneś umieszczać podwójne cudzysłowy $responsei $@aby uniknąć pomyłek, jest trochę redundantnych średników, a *warunek powinien powrócić, a nie wyjść.
Gordon Davisson

Żeby było jasne, to pojedyncze średniki na końcu niektórych instrukcji są niepotrzebne.
Wstrzymano do odwołania.

4

To może być trochę za krótkie, ale na własny użytek działa świetnie

read -n 1 -p "Push master upstream? [Y/n] " reply; 
if [ "$reply" != "" ]; then echo; fi
if [ "$reply" = "${reply#[Nn]}" ]; then
    git push upstream master
fi

The read -n 1 prostu czyta jedną postać. Nie musisz naciskać Enter. Jeśli nie jest to „n” ani „N”, przyjmuje się, że jest to „Y”. Samo naciśnięcie enter również oznacza Y.

(co do prawdziwego pytania: zrób skrypt bashowy i zmień swój alias, aby wskazywał na ten skrypt zamiast na to, co wskazywał wcześniej)


Krótkie i słodkie, właśnie tego potrzebowałem. Dzięki!
Raymo111

3
read -r -p "Are you sure? [Y/n]" response
  response=${response,,} # tolower
  if [[ $response =~ ^(yes|y| ) ]] || [[ -z $response ]]; then
      your-action-here
  fi

Więc znak spacji oznacza tak?
Xen2050,

Wszystkie oprócz „tak lub y” potwierdzą akcję, więc masz rację! @ xen2050
SergioAraujo

3

Nie trzeba naciskać Enter

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ą:

$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]?

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ź:

$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]? X
Show dangerous command [y/N]? y
rm *

Domyślnie „tak” po naciśnięciu Enter

Pamiętaj, że Ywielkie litery:

$ confirm_yes "Show dangerous command" && echo "rm *"
Show dangerous command [Y/n]?
rm *

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"
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. Uwaga: brak wielkich liter w[y/n]?

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 defualting
function 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 enter
    case "$REPLY" in
      Y|y)  return 0;;
      N|n)  return 1;;
      '')   [[ $enter_return ]] && return "$enter_return"
    esac
  done
}
    
# 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
}

2

Oto moja wersja confirm, zmodyfikowana z Jamesa:

function confirm() {
  local response msg="${1:-Are you sure} (y/[n])? "; shift
  read -r $* -p "$msg" response || echo
  case "$response" in
  [yY][eE][sS]|[yY]) return 0 ;;
  *) return 1 ;;
  esac
}

Są to następujące zmiany:

  1. służy localdo zapobiegania kolizji nazw zmiennych
  2. readużyj, $2 $3 ...aby kontrolować jego działanie, więc możesz użyć -ni-t
  3. jeśli readzakończy się niepowodzeniem, echolinia piękna dla urody
  4. My Git on Windowstylko ma bash-3.1i nie ma truelub false, więc użytkowaniareturn zamiast. Oczywiście jest to również zgodne z bash-4.4 (obecnym w Git dla Windows).
  5. użyj stylu IPython „(t / [n])”, aby wyraźnie wskazać, że „n” jest domyślnym.

2

Ta wersja pozwala mieć więcej niż jedną skrzynkę ylub Y, nlubN

  1. Opcjonalnie: Powtarzaj pytanie, dopóki nie zostanie udzielone pytanie zatwierdzające

  2. Opcjonalnie: zignoruj ​​każdą inną odpowiedź

  3. Opcjonalnie: Wyjdź z terminalu, jeśli chcesz

    confirm() {
        echo -n "Continue? y or n? "
        read REPLY
        case $REPLY in
        [Yy]) echo 'yup y' ;; # you can change what you do here for instance
        [Nn]) break ;;        # exit case statement gracefully
        # Here are a few optional options to choose between
        # Any other answer:
    
        # 1. Repeat the question
        *) confirm ;;
    
        # 2. ignore
        # *) ;;
    
        # 3. Exit terminal
        # *) exit ;;
    
        esac
        # REPLY=''
    }

Zauważ też: w ostatnim wierszu tej funkcji wyczyść zmienną REPLY. W przeciwnym razie, jeśli echo $REPLYzobaczysz, że jest nadal ustawiony, dopóki nie otworzysz lub nie zamkniesz terminalu ani nie ustawisz go ponownie.


1

Późno do gry, ale stworzyłem jeszcze jeden wariant confirmfunkcji poprzednich odpowiedzi:

confirm ()
{
    read -r -p "$(echo $@) ? [y/N] " YESNO

    if [ "$YESNO" != "y" ]; then
        echo >&2 "Aborting"
        exit 1
    fi

    CMD="$1"
    shift

    while [ -n "$1" ]; do
        echo -en "$1\0"
        shift
    done | xargs -0 "$CMD" || exit $?
}

Aby go użyć:

confirm your_command

Cechy:

  • wypisuje twoje polecenie jako część pytania
  • przekazuje argumenty za pomocą separatora NULL
  • zachowuje stan wyjścia polecenia

Robaki:

  • echo -endziała z, bashale może zawieść w twojej powłoce
  • może się nie powieść, jeśli argumenty będą kolidować z echolubxargs
  • zylion innych błędów, ponieważ skrypty powłoki są trudne

1

Próbować,

 #!/bin/bash
 pause ()
 {
 REPLY=Y
 while [ "$REPLY" == "Y" ] || [ "$REPLY" != "y" ]
 do
  echo -e "\t\tPress 'y' to continue\t\t\tPress 'n' to quit"
  read -n1 -s
      case "$REPLY" in
      "n")  exit                      ;;
      "N")  echo "case sensitive!!"   ;; 
      "y")  clear                     ;;
      "Y")  echo "case sensitive!!"   ;;
      * )  echo "$REPLY is Invalid Option"     ;;
 esac
 done
 }
 pause
 echo "Hi"

0

To nie jest dokładnie „prośba o tak lub nie”, ale tylko hack: pseudonim „ hg push ...nie do, hgpushrepoale do” hgpushrepoconfirmedpushi zanim zdołam to przeliterować, lewy mózg dokonał logicznego wyboru.


1
Ale wiesz, że użyjesz TABklucza!
Hamish Grubijan,

ok, prawda, ale przynajmniej
zerknę

0

Nie to samo, ale pomysł, który i tak działa.

#!/bin/bash  
i='y'  
while [ ${i:0:1} != n ]  
do  
    # Command(s)  
    read -p " Again? Y/n " i  
    [[ ${#i} -eq 0 ]] && i='y'  
done  

Wyjście:
Znowu? T / n N
Znowu? T / n Coś
jeszcze? T / n 7
Znowu? T / n i
ponownie? T / n nsijf
$

Teraz sprawdza tylko pierwszy znak $ i przeczytałem.


0

Poniższy kod łączy dwie rzeczy

  1. shopt -s nocasematch, który zajmie się rozróżnianiem wielkości liter

  2. a jeśli warunek, który zaakceptuje oba dane wejściowe albo przejdziesz tak, tak, tak, y.

    shopt -s nocasematch

    if [[sed-4.2.2. $ LINE = ~ (tak | y) $]]

    następnie wyjdź 0

    fi


0

Oto moje rozwiązanie, które używa zlokalizowanego wyrażenia regularnego. Tak więc w języku niemieckim również „j” dla „Ja” byłoby interpretowane jako tak.

Pierwszym argumentem jest pytanie, czy drugim argumentem jest „y” niż odpowiedź domyślna tak, w przeciwnym razie odpowiedź nie byłaby domyślna. Zwracana wartość to 0, jeśli odpowiedź brzmiała „tak” i 1, jeśli odpowiedź brzmiała „nie”.

function shure(){
    if [ $# -gt 1 ] && [[ "$2" =~ ^[yY]*$ ]] ; then
        arg="[Y/n]"
        reg=$(locale noexpr)
        default=(0 1)
    else
        arg="[y/N]"
        reg=$(locale yesexpr)
        default=(1 0)
    fi
    read -p "$1 ${arg}? : " answer
    [[ "$answer" =~ $reg ]] && return ${default[1]} || return ${default[0]}
}

Oto podstawowe zastosowanie

# basic example default is no
shure "question message" && echo "answer yes" || echo "answer no"
# print "question message [y/N]? : "

# basic example default set to yes
shure "question message" y && echo "answer yes" || echo "answer no"
# print "question message [Y/n]? : "
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.