Dans Bash, comment ajouter «Êtes-vous sûr [O / n]» à une commande ou un alias?


228

Dans ce cas particulier, je voudrais ajouter une confirmation dans Bash pour

Êtes-vous sûr? [O / n]

pour Mercurial hg push ssh://username@www.example.com//somepath/morepath, qui est en fait un alias. Existe-t-il une commande standard qui peut être ajoutée à l'alias pour y parvenir?

La raison en est que , hg pushet hg outpeut sembler similaire et parfois quand je veux hgoutrepo, je peux taper accidentlly hgpushrepo( les deux sont des alias).

Mise à jour: si cela peut être quelque chose comme une commande intégrée avec une autre commande, comme: confirm && hg push ssh://...ce serait génial ... juste une commande qui peut demander un yesou noet continuer avec le reste si yes.


1
Vous voudrez probablement utiliser une fonction au lieu d'un alias. De info bash: "Pour presque tous les usages, les fonctions shell sont préférées aux alias."
pause jusqu'à nouvel ordre.

vraiment? même pour ceux comme ls -lou rm -i?
non

5
Pour presque tous, pas tous . Soit dit en passant, ne faites jamais quelque chose comme ça alias rm='rm -i'. Un jour, lorsque vous en aurez le plus besoin, l'alias ne sera plus là et boom!quelque chose d'important sera perdu.
pause jusqu'à nouvel ordre.

attendez, si vous n'avez pas d'alias rm -i, vous ne pouvez pas compter sur un script shell également. Alors, tapez-vous toujours à rm -ichaque fois?
non

8
Il s'agit d' habitudes . Vous pouvez créer un alias comme celui de mon commentaire précédent et avoir l'habitude de taper rmet d'attendre le -icomportement, puis un jour l'alias n'est pas là (pour une raison quelconque, il n'est pas défini ou n'est pas défini ou vous êtes sur un système différent ) et vous tapez rmet il continue immédiatement la suppression des éléments sans confirmation. Oups! Cependant, si vous avez fait un alias comme alias askrm='rm -i'ça, vous serez OK, car vous obtiendrez une erreur "commande introuvable".
pause jusqu'à nouvel ordre.

Réponses:


332

Ce sont des formes plus compactes et polyvalentes de la réponse de Hamish . Ils gèrent n'importe quel mélange de lettres majuscules et minuscules:

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

Ou, pour 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

Remarque: Si $responseest une chaîne vide, cela donnera une erreur. Pour résoudre, il suffit d' ajouter des guillemets: "$response". - Utilisez toujours des guillemets doubles dans les variables contenant des chaînes (par exemple: préférez utiliser à la "$@"place $@).

Ou, Bash 4.x:

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

Éditer:

En réponse à votre modification, voici comment créer et utiliser une confirmcommande basée sur la première version de ma réponse (cela fonctionnerait de manière similaire avec les deux autres):

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
}

Pour utiliser cette fonction:

confirm && hg push ssh://..

ou

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

9
En fait, il devrait être [o / n] et non [o / n] pour le test en cours.
Simon A. Eugster

Il convient de mentionner que si vous souhaitez vérifier not equal tole deuxième exemple, vous devez convertir la $responsevariable. Par exemple: if [[ ! $response =~ ^([yY][eE][sS]|[yY])$ ]].
João Cunha

@ JoãoCunha: Ce serait "pas de correspondance" plutôt que "pas égal" puisque =~c'est l'opérateur de correspondance regex.
pause jusqu'à nouvel ordre.

@DennisWilliamson correct, c'est ce que j'ai essayé de dire. Impossible de modifier mon commentaire pour une raison quelconque.
João Cunha

6
Belle fonction générale oui / non . prend en charge une invite forte et, éventuellement, la valeur «y» ou «n» par défaut.
wkw

19

Voici à peu près un extrait que vous souhaitez. Permettez-moi de savoir comment transmettre les arguments.

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

Attention à yes | command name here:)


14

Les confirmations sont facilement contournées avec les retours chariot, et je trouve utile de demander continuellement une entrée valide.

Voici une fonction pour vous faciliter la tâche. "entrée invalide" apparaît en rouge si Y | N n'est pas reçu, et l'utilisateur est à nouveau invité.

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

Vous pouvez modifier l'invite par défaut en passant un argument


12

Pour éviter de vérifier explicitement ces variantes de 'oui', vous pouvez utiliser l'opérateur d'expression régulière bash '= ~' avec une expression régulière:

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

Cela teste si l'entrée utilisateur commence par «y» ou «Y» et est suivie par zéro ou plusieurs «es».


5

Cela peut être un hack:

comme en question Sous Unix / Bash, "xargs -p" est-il un bon moyen de demander une confirmation avant d'exécuter une commande?

nous pouvons utiliser xargspour faire le travail:

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

bien sûr, cela sera défini comme un alias, comme hgpushrepo

Exemple:

$ 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

Ajoutez ce qui suit à votre fichier / etc / bashrc. Ce script ajoute une "fonction" résidente au lieu d'un alias appelé "confirmer".


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
}

Agréable. Quelques corrections mineures, cependant: vous devez mettre des guillemets autour $responseet $@pour éviter les erreurs, il y a des points-virgules redondants, et la *condition devrait revenir, pas quitter.
Gordon Davisson

Pour être clair, ce sont les points-virgules uniques à la fin de certaines instructions qui ne sont pas nécessaires.
pause jusqu'à nouvel ordre.

4

Cela peut être un peu trop court, mais pour mon usage privé, cela fonctionne très bien

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

Le read -n 1lit juste un caractère. Pas besoin d'appuyer sur Entrée. Si ce n'est pas un «n» ou un «N», il est supposé être un «Y». Une simple pression sur enter signifie également Y.

(comme pour la vraie question: faites-en un script bash et changez votre alias pour pointer vers ce script au lieu de ce qui pointait auparavant)


Court et doux, juste ce dont j'avais besoin. Merci!
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

Donc, un caractère espace signifie oui?
Xen2050

Tout sauf «oui ou y» confirmera l'action, vous avez donc raison! @ xen2050
SergioAraujo

3

Aucune pression sur enter requise

Voici une approche plus longue, mais réutilisable et modulaire:

  • Renvoie 0= oui et 1= non
  • Aucune pression sur entrée requise - juste un seul caractère
  • Peut appuyer enterpour accepter le choix par défaut
  • Peut désactiver le choix par défaut pour forcer une sélection
  • Fonctionne pour zshet bash.

Par défaut à "non" lorsque vous appuyez sur Entrée

Notez que le Nest en majuscule. Ici, appuyez sur Entrée, en acceptant la valeur par défaut:

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

Notez également que cela a [y/N]?été automatiquement ajouté. Le "non" par défaut est accepté, donc rien n'est répété.

Invitez à nouveau jusqu'à ce qu'une réponse valide soit donnée:

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

Par défaut "oui" lorsque vous appuyez sur Entrée

Notez que le Yest en majuscule:

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

Ci-dessus, je viens d'appuyer sur Entrée, donc la commande s'est exécutée.

Aucune valeur par défaut sur enter- nécessite youn

$ 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

Ici, 1ou faux a été retourné. Notez pas de capitalisation dans[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
}

2

Eh bien, voici ma version de confirm, modifiée de celle de 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
}

Ces changements sont:

  1. utiliser localpour empêcher les noms de variables d'entrer en collision
  2. readutiliser $2 $3 ...pour contrôler son action, vous pouvez donc utiliser -net-t
  3. en cas de readsortie infructueuse, echoun fil de ligne pour la beauté
  4. mon a Git on Windowsseulement bash-3.1et n'a pas trueou false, utilisez donc à la returnplace. Bien sûr, cela est également compatible avec bash-4.4 (l'actuel dans Git pour Windows).
  5. utilisez le style IPython "(y / [n])" pour indiquer clairement que "n" est la valeur par défaut.

2

Cette version vous permet d'avoir plus d'un cas you Y, nouN

  1. Facultativement: répétez la question jusqu'à ce qu'une question d'approbation soit fournie

  2. Facultativement: ignorer toute autre réponse

  3. En option: quittez le terminal si vous le souhaitez

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

Remarquez cela aussi: sur la dernière ligne de cette fonction, effacez la variable REPLY. Sinon, si vous echo $REPLYle voyez, il est toujours réglé jusqu'à ce que vous ouvriez ou fermiez votre terminal ou le réinitialisiez.


1

Tard dans le jeu, mais j'ai créé une autre variante des confirmfonctions des réponses précédentes:

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

Pour l'utiliser:

confirm your_command

Fonctionnalités:

  • imprime votre commande dans le cadre de l'invite
  • transmet des arguments à l'aide du délimiteur NULL
  • préserve l'état de sortie de votre commande

Bugs:

  • echo -enfonctionne avec bashmais pourrait échouer dans votre shell
  • pourrait échouer si les arguments interfèrent avec echoouxargs
  • un million d'autres bogues parce que les scripts shell sont difficiles

1

Essayer,

 #!/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

Ce n'est pas exactement un "demander oui ou non" mais juste un hack: alias le hg push ...non hgpushrepomais le hgpushrepoconfirmedpushet au moment où je peux expliquer le tout, le cerveau gauche a fait un choix logique.


1
Mais vous savez que vous utiliserez la TABclé!
Hamish Grubijan

ok, vrai, mais au moins je vais jeter un coup d'œil à la commande et voir qu'elle est bizarre et y réfléchir à deux fois avant de frapper Entrée
non

0

Pas la même chose, mais l'idée qui fonctionne quand même.

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

Sortie:
encore une fois? O / n N
Encore? O / n
Encore une fois? O / n 7
Encore? O / n et
encore? O / n nsijf
$

Maintenant, ne vérifie que le premier caractère de $ i read.


0

Le code ci-dessous combine deux choses

  1. shopt -s nocasematch qui s'occupera de la casse

  2. et si la condition accepte les deux entrées, vous passez oui, oui, oui, oui.

    shopt -s nocasematch

    si [[sed-4.2.2. $ LINE = ~ (oui | y) $]]

    puis quittez 0

    Fi


0

Voici ma solution qui utilise l'expression régulière localisée. Donc en allemand aussi "j" pour "Ja" serait interprété comme oui.

Le premier argument est la question, si le deuxième argument est "y" que oui serait la réponse par défaut sinon non serait la réponse par défaut. La valeur de retour est 0 si la réponse est "oui" et 1 si la réponse est "non".

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

Voici une utilisation basique

# 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]? : "
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.