web-dev-qa-db-esp.com

En Bash, cómo agregar "¿Estás seguro de [S/n]" a cualquier comando o alias?

En este caso particular, me gustaría agregar una confirmación en Bash para

¿Estás seguro? [S/n] 

para hg Push ssh://[email protected]//somepath/morepath de Mercurial, que en realidad es un alias. ¿Hay un comando estándar que se puede agregar al alias para lograrlo?

La razón es que hg Push y hg out pueden sonar similares y, a veces, cuando quiero hgoutrepo, puedo escribir accidentalmente hgpushrepo (ambos son alias).

Actualización: si puede ser algo así como un comando incorporado con otro comando, como: confirm && hg Push ssh://... sería genial ... solo un comando que puede pedir un yes o no y continuar con el resto si yes.

196

Estas son formas más compactas y versátiles de Hamish's answer . Manejan cualquier mezcla de mayúsculas y minúsculas:

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

O, para Bash> = versión 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

Nota: Si $response es una cadena vacía, dará un error. Para corregirlo, simplemente agregue comillas: "$response". - Siempre use comillas dobles en variables que contengan cadenas (por ejemplo, prefiera usar "[email protected]" en lugar de [email protected]).

O, Bash 4.x:

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

Editar:

En respuesta a su edición, a continuación le indicamos cómo crearía y utilizaría un comando confirm basado en la primera versión de mi respuesta (funcionaría de manera similar con los otros dos):

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
}

Para utilizar esta función:

confirm && hg Push ssh://..

o

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

Aquí es más o menos un fragmento que desea. Déjame descubrir cómo reenviar los argumentos.

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

Cuidado con yes | command name here :)

19
Hamish Grubijan

Para evitar verificar explícitamente estas variantes de 'sí', puede usar el operador de expresión regular bash '= ~' con una expresión regular:

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

Eso prueba si la entrada del usuario comienza con 'y' o 'Y' y es seguida por cero o más 'es's.

11
user389850

Las confirmaciones se omiten fácilmente con retornos de carro, y me parece útil solicitar continuamente una entrada válida.

Aquí hay una función para hacer esto fácil. "entrada inválida" aparece en rojo si no se recibe Y | N, y se le vuelve a preguntar al usuario.

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

Puede cambiar la solicitud predeterminada pasando un argumento

10
briceburg

Esto puede ser un hack:

como en la pregunta En Unix/Bash, ¿es "xargs -p" una buena manera de pedir confirmación antes de ejecutar cualquier comando?

podemos usar xargs para hacer el trabajo:

echo ssh://[email protected]//somepath/morepath | xargs -p hg Push

por supuesto, esto se establecerá como un alias, como hgpushrepo

Ejemplo:

$ 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

Agregue lo siguiente a su archivo/etc/bashrc. Esta secuencia de comandos agrega una "función" residente en lugar de un alias llamado "confirmar".


function confirm( )
{
#alert the user what they are about to do.
echo "About to [email protected]";
#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
               "[email protected]"
               ;;
    *)
              #Otherwise exit...
              echo "ciao..."
              exit
              ;;
esac
}
3
MattyV

Bueno, aquí está mi versión de confirm, modificada de la 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
}

Estos cambios son:

  1. use local para evitar que los nombres de variables colisionen
  2. read usa $2 $3 ... para controlar su acción, así que puedes usar -n y -t
  3. si read sale sin éxito, echo una línea de alimentación para la belleza
  4. mi Git on Windows solo tiene bash-3.1 y no tiene true o false, así que usa return en su lugar. Por supuesto, esto también es compatible con bash-4.4 (el actual en Git para Windows).
  5. use el estilo de IPython "(y/[n])" para indicar claramente que "n" es el valor predeterminado.
2
Dahan Gong

Tarde en el juego, pero creé otra variante de las funciones confirm de respuestas anteriores:

confirm ()
{
    read -r -p "$(echo [email protected]) ? [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 $?
}

Para usarlo:

confirm your_command

Caracteristicas:

  • imprime su comando como parte del aviso
  • pasa argumentos mediante el uso del delimitador NULL
  • conserva el estado de salida de tu comando

Loco:

  • echo -en funciona con bash pero puede fallar en tu Shell
  • podría fallar si los argumentos interfieren con echo o xargs
  • un millón de otros errores porque Shell scripting es difícil
1
thomas.me

Tratar,

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

No es necesario presionar entrar

Aquí hay un enfoque más largo, pero reutilizable y modular:

  • Devuelve 0 = yes y 1 = no
  • No es necesario presionar Intro - solo un solo carácter
  • Puede presionar enter para aceptar la opción por defecto
  • Puede deshabilitar la opción predeterminada para forzar una selección
  • Funciona tanto para zsh y bash.

Predeterminado a "no" al presionar enter

Tenga en cuenta que el N está en mayúscula. Aquí se presiona enter, aceptando el valor predeterminado:

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

También tenga en cuenta, que [y/N]? se adjuntó automáticamente. Se acepta el "no" predeterminado, por lo que no se repite nada.

Re-solicitar hasta que se dé una respuesta válida:

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

Predeterminado a "sí" al presionar enter

Tenga en cuenta que el Y está en mayúscula:

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

Arriba, presioné enter, así que el comando se ejecutó.

No predeterminado en enter - requiere y o 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

Aquí, 1 o false fue devuelto. Tenga en cuenta que no hay mayúsculas en [y/n]?

Código

# 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

Aquí está mi solución que utilizando expresiones regulares localizadas. Así que en alemán también "j" para "Ja" se interpretaría como sí.

El primer argumento es la pregunta, si el segundo argumento es "y" entonces sí sería la respuesta predeterminada, de lo contrario, no sería la respuesta predeterminada El valor de retorno es 0 si la respuesta fue "sí" y 1 si la respuesta fue "no".

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

Aquí hay un uso básico.

# 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

El código de abajo combina dos cosas

  1. shopt -s nocasematch que se encargará de no tener en cuenta las mayúsculas

  2. y si la condición acepta tanto la entrada, usted pasa sí, Sí, SI, y.

    shopt -s nocasematch

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

    luego salir 0

    fi

0
Shyam Gupta

Esto no es exactamente un "pedir sí o no", sino solo un truco: alias el hg Push ... no para hgpushrepo sino para hgpushrepoconfirmedpush y para cuando pueda explicar todo el asunto, el cerebro izquierdo ha tomado una decisión lógica.

0

No es lo mismo, pero la idea funciona de todos modos.

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

Salida:
¿Otra vez? S/n N
¿Otra vez? Y/n cualquier cosa
¿Otra vez? S/n 7
¿Otra vez? Y/n &
¿Otra vez? S/n nsijf
PS

Ahora solo verifica el 1er carácter de $ i leo.

0
anonimous

Esto puede ser un poco demasiado corto, pero para mi uso privado, funciona muy bien

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

El read -n 1 solo lee un carácter. Si no es una 'n' minúscula, se supone que es una 'Y'.

(en cuanto a la pregunta real: conviértalo en un script de bash y cambie su alias para que apunte a ese script en lugar de a lo que apuntaba anteriormente)

0
commonpike