Wie füge ich in Bash einem Befehl oder Alias ​​"Sind Sie sicher [J / N]" hinzu?

228

In diesem speziellen Fall möchte ich eine Bestätigung in Bash für hinzufügen

Bist du sicher? [J / n]

für Mercurial's hg push ssh://[email protected]//somepath/morepath, was eigentlich ein Alias ​​ist. Gibt es einen Standardbefehl, der dem Alias ​​hinzugefügt werden kann, um dies zu erreichen?

Der Grund ist, dass hg pushund hg outkann ähnlich klingen und manchmal, wenn ich will hgoutrepo, kann ich versehentlich tippen hgpushrepo(beide sind Aliase).

Update: Wenn es so etwas wie ein eingebauter Befehl mit einem anderen Befehl sein kann, wie zum Beispiel: confirm && hg push ssh://...Das wäre großartig ... nur ein Befehl, der nach einem yesoder fragen nound mit dem Rest fortfahren kann, wenn yes.

Unpolarität
quelle
1
Möglicherweise möchten Sie eine Funktion anstelle eines Alias ​​verwenden. Aus info bash: "Für fast jeden Zweck werden Shell-Funktionen Aliasen vorgezogen."
Bis auf weiteres angehalten.
Ja wirklich? auch für diejenigen wie ls -loder rm -i?
Unpolarität
5
Für fast jeden, nicht für jeden . Übrigens, mach niemals so etwas alias rm='rm -i'. Eines Tages, wenn Sie es am meisten brauchen, wird der Alias ​​nicht da sein und boom!etwas Wichtiges geht verloren.
Bis auf weiteres angehalten.
Warten Sie, wenn Sie nicht über den Alias ​​verfügen rm -i, können Sie auch nicht mit einem Shell-Skript rechnen. Also tippst du immer rm -ijedes Mal?
Unpolarität
8
Es geht um Gewohnheiten . Sie könnten einen Alias ​​wie den in meinem vorherigen Kommentar erstellen rmund das -iVerhalten eingeben und erwarten . Dann ist der Alias ​​eines Tages nicht mehr vorhanden (aus irgendeinem Grund wird er nicht gesetzt oder nicht gesetzt oder Sie befinden sich auf einem anderen System ) und Sie tippen rmund es geht sofort los, Dinge ohne Bestätigung zu löschen. Hoppla! Wenn Sie jedoch einen Alias ​​wie diesen erstellt alias askrm='rm -i'haben, ist dies in Ordnung, da der Fehler "Befehl nicht gefunden" angezeigt wird.
Bis auf weiteres angehalten.

Antworten:

332

Dies sind kompaktere und vielseitigere Formen der Antwort von Hamish . Sie verarbeiten jede Mischung aus Groß- und Kleinbuchstaben:

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

Oder für Bash> = Version 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

Hinweis: Wenn $responsees sich um eine leere Zeichenfolge handelt, wird ein Fehler ausgegeben. Fügen Sie zum Beheben einfach Anführungszeichen hinzu : "$response". - Verwenden Sie immer doppelte Anführungszeichen in Variablen enthalten Zeichenketten (zB: lieber verwenden "$@"statt $@).

Oder Bash 4.x:

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

Bearbeiten:

Als Antwort auf Ihre Bearbeitung würden Sie wie folgt einen confirmBefehl erstellen und verwenden, der auf der ersten Version in meiner Antwort basiert (dies würde ähnlich mit den beiden anderen funktionieren):

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
}

So verwenden Sie diese Funktion:

confirm && hg push ssh://..

oder

confirm "Would you really like to do a push?" && hg push ssh://..
Bis auf weiteres angehalten.
quelle
9
Eigentlich sollte es für den aktuellen Test [J / N] und nicht [J / N] sein.
Simon A. Eugster
Erwähnenswert ist, dass Sie not equal todie $responseVariable umwandeln sollten , wenn Sie das zweite Beispiel überprüfen möchten . ZB : if [[ ! $response =~ ^([yY][eE][sS]|[yY])$ ]].
João Cunha
@ JoãoCunha: Das wäre eher "nicht übereinstimmen" als "nicht gleich", da =~es sich um den Regex-Übereinstimmungsoperator handelt.
Bis auf weiteres angehalten.
@ TennisWilliamson richtig, das habe ich versucht zu meinen. Ich kann meinen Kommentar aus irgendeinem Grund nicht bearbeiten.
João Cunha
6
Schöne allgemeine Ja / Nein-Funktion . unterstützt eine starke Eingabeaufforderung und wählt optional 'y' oder 'n' als Standard.
Woche
19

Hier ist ungefähr ein Ausschnitt, den Sie wollen. Lassen Sie mich herausfinden, wie die Argumente weitergeleitet werden.

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

Achtung yes | command name here:)

Hamish Grubijan
quelle
13

Bestätigungen können mit Wagenrückläufen leicht umgangen werden, und ich finde es nützlich, ständig nach gültigen Eingaben zu fragen.

Hier ist eine Funktion, um dies zu vereinfachen. "Ungültige Eingabe" wird rot angezeigt, wenn Y | N nicht empfangen wird, und der Benutzer wird erneut aufgefordert.

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

Sie können die Standardaufforderung ändern, indem Sie ein Argument übergeben

Briceburg
quelle
12

Um zu vermeiden, dass explizit nach diesen Varianten von 'yes' gesucht wird, können Sie den Bash-Operator für reguläre Ausdrücke '= ~' mit einem regulären Ausdruck verwenden:

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

Dadurch wird geprüft, ob die Benutzereingabe mit 'y' oder 'Y' beginnt und auf null oder mehr 'es' folgt.

user389850
quelle
5

Dies kann ein Hack sein:

Wie in Frage : Ist "xargs -p" in Unix / Bash eine gute Möglichkeit, vor dem Ausführen eines Befehls zur Bestätigung aufzufordern?

wir können verwenden xargs, um die Arbeit zu erledigen:

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

Natürlich wird dies als Alias ​​gesetzt, wie hgpushrepo

Beispiel:

$ 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

$
Unpolarität
quelle
4

Fügen Sie Ihrer Datei / etc / bashrc Folgendes hinzu. Dieses Skript fügt eine residente "Funktion" anstelle eines Alias ​​namens "Bestätigen" hinzu.


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
}
MattyV
quelle
Nett. Einige kleinere Korrekturen: Sie sollten doppelte Anführungszeichen setzen $responseund $@um Fehlanalysen zu vermeiden, gibt es einige redundante Semikolons, und die *Bedingung sollte zurückkehren und nicht beenden .
Gordon Davisson
Um ganz klar zu sein, es sind die einzelnen Semikolons am Ende einiger Anweisungen, die nicht erforderlich sind.
Bis auf weiteres angehalten.
4

Das mag etwas zu kurz sein, aber für meinen privaten Gebrauch funktioniert es großartig

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

Der read -n 1liest nur ein Zeichen. Sie müssen nicht die Eingabetaste drücken. Wenn es kein 'n' oder 'N' ist, wird angenommen, dass es ein 'Y' ist. Nur die Eingabetaste zu drücken bedeutet auch Y.

(Was die eigentliche Frage betrifft: Machen Sie das zu einem Bash-Skript und ändern Sie Ihren Alias ​​so, dass er auf dieses Skript verweist, anstatt auf das, worauf zuvor verwiesen wurde.)

Commonpike
quelle
Kurz und bündig, genau das, was ich brauchte. Vielen Dank!
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
SergioAraujo
quelle
Ein Leerzeichen bedeutet also ja?
Xen2050
Alle außer "Ja oder Ja" bestätigen die Aktion, also haben Sie Recht! @ Xen2050
SergioAraujo
3

Keine Eingabetaste erforderlich

Hier ist ein längerer, aber wiederverwendbarer und modularer Ansatz:

  • Rückgabe 0= ja und 1= nein
  • Kein Drücken der Eingabetaste erforderlich - nur ein einzelnes Zeichen
  • Kann drücken enter, um die Standardauswahl zu akzeptieren
  • Kann die Standardauswahl deaktivieren, um eine Auswahl zu erzwingen
  • Funktioniert für beide zshund bash.

Standardmäßig "Nein", wenn Sie die Eingabetaste drücken

Beachten Sie, dass das Ngroß geschrieben ist. Hier wird die Eingabetaste gedrückt, wobei die Standardeinstellung übernommen wird:

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

Beachten Sie auch, dass dies [y/N]?automatisch angehängt wurde. Das Standard "Nein" wird akzeptiert, daher wird nichts wiedergegeben.

Erneut auffordern, bis eine gültige Antwort gegeben wird:

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

Standardmäßig "Ja", wenn Sie die Eingabetaste drücken

Beachten Sie, dass das Ygroß geschrieben wird:

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

Oben habe ich nur die Eingabetaste gedrückt, sodass der Befehl ausgeführt wurde.

Kein Standard ein enter- erfordern yodern

$ 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

Hier 1oder falsch wurde zurückgegeben. Beachten Sie keine Großschreibung in[y/n]?

Code

# 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
}
Tom Hale
quelle
2

Nun, hier ist meine Version von confirm, modifiziert von James ':

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
}

Diese Änderungen sind:

  1. Verwenden Sie localdiese Option, um zu verhindern, dass Variablennamen kollidieren
  2. readverwenden $2 $3 ...ihre Wirkung zu steuern, so können Sie verwenden , -nund-t
  3. Wenn readerfolglos beendet wird, wird echoein Zeilenvorschub für Schönheit erstellt
  4. mein Git on Windowseinziges hat bash-3.1und hat kein trueoder false, also benutze returnstattdessen. Dies ist natürlich auch mit bash-4.4 (dem aktuellen in Git für Windows) kompatibel.
  5. Verwenden Sie den IPython-Stil "(y / [n])", um deutlich anzuzeigen, dass "n" die Standardeinstellung ist.
Dahan Gong
quelle
2

Mit dieser Version können Sie mehr als einen Fall haben , yoder Y, noderN

  1. Optional: Wiederholen Sie die Frage, bis eine genehmigende Frage bereitgestellt wird

  2. Optional: Ignorieren Sie jede andere Antwort

  3. Optional: Verlassen Sie das Terminal, wenn Sie möchten

    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=''
    }

Beachten Sie auch Folgendes: Löschen Sie in der letzten Zeile dieser Funktion die Variable REPLY. Andernfalls wird es, wenn Sie echo $REPLYsehen, immer noch eingestellt, bis Sie Ihr Terminal öffnen oder schließen oder erneut einstellen.

jasonleonhard
quelle
1

Spät zum Spiel, aber ich habe noch eine andere Variante der confirmFunktionen früherer Antworten erstellt:

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 $?
}

Um es zu benutzen:

confirm your_command

Eigenschaften:

  • druckt Ihren Befehl als Teil der Eingabeaufforderung
  • Übergibt Argumente mithilfe des NULL-Trennzeichens
  • behält den Exit-Status Ihres Befehls bei

Bugs:

  • echo -enfunktioniert mit, kann bashaber in Ihrer Shell fehlschlagen
  • kann fehlschlagen, wenn Argumente mit echooder störenxargs
  • zig andere Fehler, weil Shell-Scripting schwierig ist
thomas.me
quelle
1

Versuchen,

 #!/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"
Ranjithkumar T.
quelle
0

Dies ist nicht gerade ein "Nach Ja oder Nein fragen", sondern nur ein Hack: Alias ​​das hg push ...Nicht-zu- hgpushrepoaber zu hgpushrepoconfirmedpushund bis ich das Ganze buchstabieren kann, hat die linke Gehirnhälfte eine logische Entscheidung getroffen.

Unpolarität
quelle
1
Aber Sie wissen, dass Sie den TABSchlüssel verwenden werden!
Hamish Grubijan
ok, stimmt, aber zumindest werde ich einen Blick auf den Befehl
werfen
0

Nicht das gleiche, aber eine Idee, die trotzdem funktioniert.

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

Ausgabe:
Wieder? J / n N
Schon wieder? J / n
Wieder etwas? J / n 7
Schon wieder? J / n & schon
wieder? J / n nsijf
$

Überprüft jetzt nur das erste Zeichen von $ i read.

anonym
quelle
0

Der folgende Code kombiniert zwei Dinge

  1. shopt -s nocasematch, das sich um Groß- und Kleinschreibung kümmert

  2. und wenn eine Bedingung vorliegt, die beide Eingaben akzeptiert, übergeben Sie entweder yes, Yes, YES, y.

    shopt -s nocasematch

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

    dann beenden Sie 0

    fi

Shyam Gupta
quelle
0

Hier ist meine Lösung, die lokalisierte Regex verwendet. Auf Deutsch würde also auch "j" für "Ja" als ja interpretiert werden.

Das erste Argument ist die Frage, wenn das zweite Argument "y" ist, wäre "Ja" die Standardantwort, andernfalls "Nein" die Standardantwort. Der Rückgabewert ist 0, wenn die Antwort "Ja" war, und 1, wenn die Antwort "Nein" war.

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]}
}

Hier ist eine grundlegende Verwendung

# 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]? : "
David Boho
quelle