In Bash, how to add “Are you sure [Y/n]” to any command or alias?

前端 未结 17 2882
轮回少年
轮回少年 2020-11-29 15:11

In this particular case, I\'d like to add a confirm in Bash for

Are you sure? [Y/n]

for Mercurial\'s hg push ssh://username@www.example.com//some

相关标签:
17条回答
  • 2020-11-29 15:12

    This isn't exactly an "asking for yes or no" but just a hack: alias the hg push ... not to hgpushrepo but to hgpushrepoconfirmedpush and by the time I can spell out the whole thing, the left brain has made a logical choice.

    0 讨论(0)
  • 2020-11-29 15:13

    No pressing enter required

    Here's a longer, but reusable and modular approach:

    • Returns 0=yes and 1=no
    • No pressing enter required - just a single character
    • Can press enter to accept the default choice
    • Can disable default choice to force a selection
    • Works for both zsh and bash.

    Defaulting to "no" when pressing enter

    Note that the N is capitalsed. Here enter is pressed, accepting the default:

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

    Also note, that [y/N]? was automatically appended. The default "no" is accepted, so nothing is echoed.

    Re-prompt until a valid response is given:

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

    Defaulting to "yes" when pressing enter

    Note that the Y is capitalised:

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

    Above, I just pressed enter, so the command ran.

    No default on enter - require y or 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
    

    Here, 1 or false was returned. Note no capitalisation 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
    }
    
    0 讨论(0)
  • 2020-11-29 15:16

    Add the following to your /etc/bashrc file. This script adds a resident "function" instead of an alias called "confirm".


    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
    }
    
    0 讨论(0)
  • 2020-11-29 15:18

    Not the same, but idea that works anyway.

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

    Output:
    Again? Y/n N
    Again? Y/n Anything
    Again? Y/n 7
    Again? Y/n &
    Again? Y/n nsijf
    $

    Now only checks 1st character of $i read.

    0 讨论(0)
  • 2020-11-29 15:22

    This may be a little too short, but for my own private use, it works great

    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 just reads one character. No need to hit enter. If it's not a 'n' or 'N', it is assumed to be a 'Y'. Just pressing enter means Y too.

    (as for the real question: make that a bash script and change your alias to point to that script instead of what is was pointing to before)

    0 讨论(0)
  • 2020-11-29 15:24

    This may be a hack:

    as in question In Unix / Bash, is "xargs -p" a good way to prompt for confirmation before running any command?

    we can using xargs to do the job:

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

    of course, this will be set as an alias, like hgpushrepo

    Example:

    $ 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
    
    $
    
    0 讨论(0)
提交回复
热议问题