web-dev-qa-db-fra.com

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

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

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

pour hg Push ssh://[email protected]//somepath/morepath de Mercurial, qui est en fait un alias. Existe-t-il une commande standard pouvant être ajoutée à l'alias pour y parvenir?

La raison en est que hg Push et hg out peuvent sembler similaires et parfois lorsque je veux hgoutrepo, je peux taper accidentellement hgpushrepo (les deux sont des alias).

Mise à jour: si cela peut ressembler à une commande intégrée avec une autre commande, telle que: confirm && hg Push ssh://... ça serait génial ... juste une commande qui peut demander un yes ou no et continuez si yes.

205

Ce sont des formes plus compactes et plus polyvalentes de (Réponse de Hamish . Ils gèrent tout 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 $response est une chaîne vide, une erreur se produira. Pour résoudre ce problème, ajoutez simplement des guillemets: "$response". - Utilisez toujours des guillemets doubles dans les variables contenant des chaînes (par exemple: préférez utiliser "$@" à la place de $@).

Ou, Bash 4.x:

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

Modifier:

En réponse à votre modification, voici comment créer et utiliser une commande confirm basée sur la première version de ma réponse (qui fonctionnerait de la même manière 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://..
299
Dennis Williamson

Voici à peu près un extrait que vous voulez. 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 :)

19
Hamish Grubijan

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

Voici une fonction pour rendre cela facile. "entrée invalide" apparaît en rouge si Y | N n'est pas reçu et que l'utilisateur est invité à nouveau.

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 changer l'invite par défaut en passant un argument

11
briceburg

Pour éviter de rechercher 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 de zéro ou plus.

11
user389850

Cela peut être un bidouillage:

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

nous pouvons utiliser xargs pour faire le travail:

echo ssh://[email protected]//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
read -r -p "Are you sure? [Y/n]" response
  response=${response,,} # tolower
  if [[ $response =~ ^(yes|y| ) ]] || [[ -z $response ]]; then
      your-action-here
  fi
3
SergioAraujo

Ajoutez les éléments suivants à 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
}
3
MattyV

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. utilisez local pour empêcher les noms de variables d'entrer en collision
  2. read utilise $2 $3 ... pour contrôler son action. Vous pouvez donc utiliser -n et -t
  3. si read se ferme sans succès, echo un saut de ligne pour la beauté
  4. mon Git on Windows n'a que bash-3.1 et n'a ni true ni false, utilisez donc return à la place. Bien entendu, cela est également compatible avec bash-4.4 (le dernier dans Git pour Windows).
  5. utilisez le style IPython "(y/[n])" pour indiquer clairement que "n" est la valeur par défaut.
2
Dahan Gong

En retard au jeu, mais j’ai créé une autre variante des fonctions confirm 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
  • passe des arguments en utilisant le délimiteur NULL
  • préserve l'état de sortie de votre commande

Bogues:

  • echo -en fonctionne avec bash mais peut échouer dans votre shell
  • peut échouer si les arguments interfèrent avec echo ou xargs
  • un zillion d'autres bugs parce que les scripts Shell sont difficiles
1
thomas.me

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"
1
Ranjithkumar T

Pas de pression nécessaire pour entrer

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

  • Renvoie 0 = yes et 1 = no
  • Aucune pression requise pour entrer - juste un seul caractère
  • Peut appuyer enter accepter le choix par défaut
  • Peut désactiver le choix par défaut pour forcer une sélection
  • Fonctionne pour zsh et bash.

La valeur par défaut est "non" lorsque vous appuyez sur Entrée.

Notez que la N est en majuscule. Ici, appuyez sur Entrée pour accepter la valeur par défaut:

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

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

Ré-invite 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 *

La valeur par défaut est "oui" lorsque vous appuyez sur Entrée.

Notez que la Y est en majuscule:

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

Ci-dessus, j'ai juste appuyé sur Entrée, donc la commande a été exécutée.

Pas de défaut sur enter - nécessite y ou n

$ 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, 1 ou false a été renvoyé. 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
}
1
Tom Hale

C’est peut-être un peu trop court, mais pour mon propre 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 1 ne lit qu'un caractère. Pas besoin d'appuyer sur entrer. Si ce n'est pas un "n" ou un "N", on suppose qu'il s'agit d'un "Y". Il suffit d'appuyer sur Entrée signifie aussi Y.

(comme pour la vraie question: faites-en un script bash et changez votre alias pour qu'il pointe vers ce script au lieu de ce qui était indiqué auparavant)

1
commonpike

Voici ma solution qui utilise regex 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", alors 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 un usage de base

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

Le code ci-dessous combine deux choses

  1. shopt -s nocasematch qui tiendra compte de la casse

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

    shopt -s nocasematch

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

    puis sortie 0

    fi

0
Shyam Gupta

Ce n'est pas exactement un "demander oui ou non" mais juste un hack: alias le hg Push ... non pas pour hgpushrepo mais pour hgpushrepoconfirmedpush et au moment où je peux tout épeler , le cerveau gauche a fait un choix logique.

0

Pas la même chose, mais une 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? O/n N
Encore? Y/n n'importe quoi
Encore? O/n 7
Encore? Y/n &
Encore? Y/n nsijf
$

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

0
anonimous