Bash: Hide user input/password

Sometimes we may need to hide the user input so that they won’t be shown in the terminal. This is especially useful when our script requires a password from users.

tl;dr

1. read -s

We can use the command read with option -s to read the password. It would not echo the input coming from the terminal when the option -s is specified.

For example:

#!/bin/bash

read -s -p "Enter password: " password
echo
echo "password: $password"

Example output:

noob@learnfromnoobs:~$ ./input_password_read.sh 
Enter password: 
password: 123456

For more information, please refer to read --help.

2. stty

We can just wrap stty -echo and stty echo between our code block that asks for user input. It turns off echo for the code block asking for user input, so nothing is output for that part.

For example:

#!/bin/bash

stty -echo
echo -n "Enter password: "
read password
echo
echo "password: $password"
stty echo

Example output:

noob@learnfromnoobs:~$ ./input_password_stty.sh 
Enter password: 
password: 123456

Notice that we cannot see our input when we type our password. The results for both methods should be exactly the same.
That’s it! Of course, don’t use a password like “123456” in our case!


ts;wm

What is stty?

According to the manpage of stty, stty is a utility to change and print terminal line settings.
If stty is run without arguments, it prints the baud rate, line discipline number and line settings that have been changed from the values set by ‘stty sane’.

noob@learnfromnoobs:~$ stty
speed 38400 baud; line = 0;
-brkint ixoff -imaxbel iutf8

Let’s try to turn off echo and then run stty again. As the echo is turned off, it is normal that you cannot see yourself typing stty. We can see that “-echo” now appears at the bottom line, indicating the echo is turned off.

noob@learnfromnoobs:~$ stty -echo
noob@learnfromnoobs:~$ speed 38400 baud; line = 0;
-brkint ixoff -imaxbel iutf8
-echo

We can view all current stty configurations using the command stty -a.

noob@learnfromnoobs:~$ stty -a
speed 38400 baud; rows 46; columns 104; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>;
start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon ixoff -iuclc -ixany -imaxbel
iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho
-extproc

For more information about stty, please refer to man stty or info stty.

Using asterisk instead of blank

Note that this approach will expose the length of your password. I would prefer just hiding the user input completely. But if you really want, you can try the approaches below.

1. systemd-ask-password if available

If the utility systemd-ask-password is available, we can just use it to get the password.
Note that there is a default 60-second timeout. We can specify the option --timeout=0 if we don’t want any timeout.

#!/bin/bash

password=`systemd-ask-password "Enter password:"`
echo "password: $password"

Example output:

noob@learnfromnoobs:~$ ./input_password_systemd.sh
Enter password: ******
password: 123456

2. Write it yourself.

If you don’t like the systemd-ask-password approach (or simply want to use a character other than ‘*’), you can write your implementation. This can also be a fun exercise.

Our implementation should allow deleting characters.
To accomplish this, our script needs to be able to handle backspace and EOL.
We also need to make sure that we are not deleting the prompt.

#!/bin/bash

unset password
unset chartCount

echo -n "Enter password: "

while IFS= read -r -n1 -s char; do
    case "$char" in
    $'\0')
        break
        ;;
    $'\177')
        if [ ${#password} -gt 0 ]; then
            echo -ne "\b \b"
            password=${password::-1}
        fi
        ;;
    *)
        chartCount=$((chartCount+1))
        echo -n '*'
        password+="$char"
        ;;
    esac
done

echo
echo "password: $password"

Example output:

noob@learnfromnoobs:~$ ./input_password_asterisk.sh 
Enter password: ******
password: 123456

Some notes for the script:

  1. IFS= is used in the while loop to make sure the loop won’t break on passwords that contain spaces. For more information, look for “IFS” in man bash.
  2. -r is used in the read command to allow passwords containing backslashes.
  3. echo -ne "\b \b" is used to erase 1 character in the password. \b moves the cursor left for 1 character. Then we output a space character ” “. And finally using \b to move the cursor 1 character left again. These are the complete actions of erasing 1 character. The option -e is needed to enable interpretation of backslash escapes.

Conclusion

In summary, we have provided 4 methods to hide password or user input in bash:

  1. Using read -s
  2. Using stty -echo
  3. Using systemd-ask-password
  4. Write your own implementation

No matter which method you have chosen finally, I hope you enjoyed this article.

Keep learning and have fun!

Leave a Reply

Your email address will not be published. Required fields are marked *