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

53,666

Solution 1

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"

Solution 2

I really liked the answer that Wirone gave, but I didn't like that the backspacing would continue removing characters even back into the "Enter password: " prompt.

I also had some issues where pressing keys too rapidly would cause some of the characters to actually print on the screen... never a good thing when prompting for a password. =)

The following is my modified version of Wirone's answer which addresses these issues:

#!/bin/bash

unset PASSWORD
unset CHARCOUNT

echo -n "Enter password: "

stty -echo

CHARCOUNT=0
while IFS= read -p "$PROMPT" -r -s -n 1 CHAR
do
    # Enter - accept password
    if [[ $CHAR == $'\0' ]] ; then
        break
    fi
    # Backspace
    if [[ $CHAR == $'\177' ]] ; then
        if [ $CHARCOUNT -gt 0 ] ; then
            CHARCOUNT=$((CHARCOUNT-1))
            PROMPT=$'\b \b'
            PASSWORD="${PASSWORD%?}"
        else
            PROMPT=''
        fi
    else
        CHARCOUNT=$((CHARCOUNT+1))
        PROMPT='*'
        PASSWORD+="$CHAR"
    fi
done

stty echo

echo $PASSWORD

Solution 3

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.

Solution 4

I would like to add something to Dennis Williamson's solution:

#!/bin/bash

unset password
echo -n "Enter password: "
while IFS= read -p "$prompt" -r -s -n 1 char
do
    # Enter - accept password
    if [[ $char == $'\0' ]] ; then
        break
    fi
    # Backspace
    if [[ $char == $'\177' ]] ; then
        prompt=$'\b \b'
        password="${password%?}"
    else
        prompt='*'
        password+="$char"
    fi
done

In above example script handles backspace correctly.

Source

Solution 5

I don't know about stars, but stty -echo is your friend:

 #!/bin/sh 
 read -p "Username: " uname 
 stty -echo 
 read -p "Password: " passw; echo 
 stty echo

Source: http://www.peterbe.com/plog/passwords-with-bash

Share:
53,666
Deniz Zoeteman
Author by

Deniz Zoeteman

Back-end (web)development. Specialised mostly in PHP.

Updated on July 09, 2022

Comments

  • Deniz Zoeteman
    Deniz Zoeteman almost 2 years

    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 something in using read?

  • SiegeX
    SiegeX over 13 years
    You need to unset IFS or add IFS= to your while loop otherwise your loop will prematurely break on passwords that contain spaces. Also, you should add the -r flag to read so that passwords can contain backslashes.
  • Brad Mace
    Brad Mace over 11 years
    password+="$char" didn't work on my system. I had to do password="${password}${char}" instead.
  • SourceSeeker
    SourceSeeker over 11 years
    @BradMace: You must not be using Bash, ksh (93) or zsh or you are using a very old version of Bash (e.g. 2.05b).
  • kratenko
    kratenko almost 10 years
    I'm far from beeing a bash-expert, but I think this code has several issues (like password having a fixed length of 6 and not working with backspaces)
  • Keith Thompson
    Keith Thompson almost 10 years
    That hardly seems necessary since read has a -s option (the question is tagged bash so we can assume bash-specific features). Interrupting the read command (e.g., by typing control-C) could leave the tty in -echo mode.
  • Keith Thompson
    Keith Thompson almost 10 years
    It handles DEL "correctly". It doesn't do anything special with backspace (Ctrl-H).
  • Wirone
    Wirone almost 10 years
    "Normal" users rather use standard backspace, not Ctrl+H. Above script does not handle correctly arrow keys too, but hey, it's better to handle backspace and not handle Ctrl+H, or don't handle both? ;)
  • Keith Thompson
    Keith Thompson almost 10 years
    Ctrl-H is backspace (the Unicode standard calls it BACKSPACE). $'\177' is DEL (Unicode calls it DELETE). Some terminal programs may optionally map the Backspace key to the DEL character, but many "normal" users, including myself, map it to the backspace (Ctrl-H) character. A robust solution would examine the user's tty settings.
  • Wirone
    Wirone almost 10 years
    I didn't mean Unicode. I said only that for standard user backspace is a key on the keyboard, with "backspace" label ;) And this is what is mapped in script.
  • Keith Thompson
    Keith Thompson almost 10 years
    What I wrote applies to Unicode, ASCII, and Latin-N for various values of N. $'\177' is the DEL character; the backspace character is $'\010' or '\b'. What "standard" are you referring to? (When I type Ctrl-V Backspace at a shell prompt, it echoes ^H; am I violating some standard?)
  • Wirone
    Wirone almost 10 years
    Dude, I just refer to keyboard layout. I didn't see $'\177', $'\010' nor '\b' on any button. I didn't mean any standards like ASCII. Backspace is considered to delete char before caret, DEL - after it, user does not have to know what char/code it sends. EOT.
  • Keith Thompson
    Keith Thompson almost 10 years
    Dude, the backspace key on my keyboard sends an ASCII BS character (8), not an ASCII DEL character (127). My tty settings are such that typing backspace deletes the character before the cursor. It's configurable, and your code assumes a particular configuration that is not universal. There is nothing non-standard or abnormal about my setup, and your code would not work properly with it.
  • Starfish
    Starfish almost 10 years
    Instead of hardcoding the character for the backspace, add backspace=$(tput kbs) before entering the loop and then compare $char against $backspace. That way it'll work no matter what value the user has set their backspace key to send.
  • Wirone
    Wirone almost 10 years
    Thanks for tput, but to be 100% sure it's working we need to know if user has tput in path, which is not obvious (I didn't have, because I'm using Cygwin and had to install ncurses to get it). Will try to implement it meanwhile ;)
  • anthony
    anthony over 7 years
    A more advance version is ask_password_stars. It was developed as part of my personal notes on Cryptogrphy, Password Input.
  • anthony
    anthony over 7 years
    A more advance version is ask_password_stars. It was developed as part of my personal notes on Cryptogrphy, Password Input.
  • anthony
    anthony over 7 years
    He wants some feedback, not noecho silence!