How do I echo stars (*) when reading password with `read`?

后端 未结 10 803
死守一世寂寞
死守一世寂寞 2020-11-29 02:13

What do I need to do for code in Bash, if I want to echo *s in place of password characters (or even just hide the characters completely) when the user types so

相关标签:
10条回答
  • 2020-11-29 02:21

    I just made this Bash-specific function based on Dennis Williamson's, Wirone's and Logan VanCuren's answers:

    ask() {
      local 'args' 'char' 'charcount' 'prompt' 'reply' 'silent'
    
      # Basic arguments parsing
      while [[ "${1++}" ]]; do
        case "${1}" in
          ( '--silent' | '-s' )
            silent='yes'
            ;;
          ( '--' )
            args+=( "${@:2}" )
            break
            ;;
          ( * )
            args+=( "${1}" )
            ;;
        esac
        shift || break
      done
    
      if [[ "${silent}" == 'yes' ]]; then
        for prompt in "${args[@]}"; do
          charcount='0'
          prompt="${prompt}: "
          reply=''
          while IFS='' read -n '1' -p "${prompt}" -r -s 'char'; do
            case "${char}" in
              # Handles NULL
              ( $'\000' )
                break
                ;;
              # Handles BACKSPACE and DELETE
              ( $'\010' | $'\177' )
                if (( charcount > 0 )); then
                  prompt=$'\b \b'
                  reply="${reply%?}"
                  (( charcount-- ))
                else
                  prompt=''
                fi
                ;;
              ( * )
                prompt='*'
                reply+="${char}"
                (( charcount++ ))
                ;;
            esac
          done
          printf '\n' >&2
          printf '%s\n' "${reply}"
        done
      else
        for prompt in "${args[@]}"; do
          IFS='' read -p "${prompt}: " -r 'reply'
          printf '%s\n' "${reply}"
        done
      fi
    }
    

    It could be used like:

    $ ask Username
    Username: AzureDiamond
    AzureDiamond
    
    $ ask -s Password
    Password: *******
    hunter2
    
    $ ask First Second Third
    First: foo
    foo
    Second: bar
    bar
    Third: baz
    baz
    
    0 讨论(0)
  • 2020-11-29 02:22
    stty -echo
    read something
    stty echo
    

    will stop user input being echoed to the screen for that read. Depending on what you are doing with prompts, you may want to add an extra echo command to generate a newline after the read.

    0 讨论(0)
  • 2020-11-29 02:25

    If you don't care about it being interactive, you can simply do

    read -s pass
    echo "$pass" | sed 's/./*/g'
    

    This will show a * for each character of the entered password after enter is pressed.

    0 讨论(0)
  • 2020-11-29 02:27

    @nxnev's answer didn't quite work for me, at least on macOS. I simplified it a bit, and now it's flawless:

    #!/bin/bash
    
    ask() {
        charcount='0'
        prompt="${1}: "
        reply=''
        while IFS='' read -n '1' -p "${prompt}" -r -s 'char'
        do
            case "${char}" in
                # Handles NULL
                ( $'\000' )
                break
                ;;
                # Handles BACKSPACE and DELETE
                ( $'\010' | $'\177' )
                if (( charcount > 0 )); then
                    prompt=$'\b \b'
                    reply="${reply%?}"
                    (( charcount-- ))
                else
                    prompt=''
                fi
                ;;
                ( * )
                prompt='*'
                reply+="${char}"
                (( charcount++ ))
                ;;
            esac
        done
        printf '\n' >&2
        printf '%s\n' "${reply}"
    }
    
    pwd="$(ask Password)"
    
    echo "Your password is $pwd"
    
    0 讨论(0)
  • 2020-11-29 02:32

    As Mark Rushakoff pointed out, read -s will suppress the echoing of characters typed at the prompt. You can make use of that feature as part of this script to echo asterisks for each character typed:

    #!/bin/bash
    unset password
    prompt="Enter Password:"
    while IFS= read -p "$prompt" -r -s -n 1 char
    do
        if [[ $char == $'\0' ]]
        then
            break
        fi
        prompt='*'
        password+="$char"
    done
    echo
    echo "Done. Password=$password"
    
    0 讨论(0)
  • 2020-11-29 02:33

    read -s should put it in silent mode:

    -s     Silent mode.  If input is coming from a terminal, characters are not echoed.
    

    See the read section in man bash.

    0 讨论(0)
提交回复
热议问题