3. Reading keyboard input
-
The script
test-integer2.sh
, that we have seen previously, has the value ofINT
hardcoded, so that we need to edit the script in order to test another value. We can make it more interactive by using the commandread
:read-integer.sh
#!/bin/bash
# read-integer: evaluate the value of an integer.
echo -n "Please enter an integer -> "
read int
if [[ ! "$int" =~ ^-?[0-9]+$ ]]; then
echo "Input value is not an integer." >&2
exit 1
fi
if ((int == 0)); then
echo "$int is zero."
else
if ((int < 0)); then
echo "$int is negative."
else
echo "$int is positive."
fi
if (( ((int % 2)) == 0)); then
echo "$int is even."
else
echo "$int is odd."
fi
fivim read-integer.sh
./read-integer.sh # enter 0
./read-integer.sh # enter 7
./read-integer.sh # enter 4
./read-integer.sh # enter -3
./read-integer.sh # enter -8
The command read assigns the input to the variable
int
. If no variable name is given, then it assigns the input to the variableREPLY
. -
The command
read
can also get multiple variable names, as in this example:read-multiple.sh
#!/bin/bash
# read-multiple: read multiple values from keyboard
echo -n "Enter one or more values > "
read var1 var2 var3 var4 var5
echo "var1 = '$var1'"
echo "var2 = '$var2'"
echo "var3 = '$var3'"
echo "var4 = '$var4'"
echo "var5 = '$var5'"vim read-multiple.sh
In this script, we assign and display up to five values.
./read-multiple.sh # enter: a b c d e
./read-multiple.sh # enter: a b
./read-multiple.sh # enter: a b c d e f g
-
It can also get some options:
help read | less
With the
-p
option we can provide a prompt string:read -p "Enter one or more values > " # enter: a b c
echo "REPLY = '$REPLY'"
The option
-s
can be used for a silent input, and-t
to set a timeout. Let's see them in an example that tries to read a password:read-user-pass.sh
#!/bin/bash
# -e: use readline to get the input
# -p: display a prompt
# -i: provide a default reply
read -e -p "What is your user name > " -i $USER username
echo "Welcome '$username'"
# -t: timeout (in seconds)
# -s: silent (do not echo characters to the display as they are typed)
# -p: display a prompt
if read -t 10 -sp "Enter your secret passphrase > " secret_pass
then
echo -e "\nYour secret passphrase is '$secret_pass'"
else
echo -e "\nInput timed out" >&2
exit 1
fivim read-user-pass.sh
./read-user-pass.sh
If we don't type a password in 10 seconds, the
read
command will time out with an error exit code. -
The input provided to
read
is split by the shell. There is a shell variable namedIFS
(Internal Field Separator) which contains a list of separators. By default it contains a space, a tab, and a newline character. Each of them can separate items from each-other.If we want to modify the way that the input is separated into fields, we can change the value of
IFS
.read-ifs.sh
#!/bin/bash
# read-ifs: read fields from a file
read -p "Enter a username > " user_name
file_info="$(grep "^$user_name:" /etc/passwd)"
if [ -z "$file_info" ]; then
echo "No such user '$user_name'" >&2
exit 1
fi
IFS=":" read user pw uid gid name home shell <<< "$file_info"
echo "User = '$user'"
echo "UID = '$uid'"
echo "GID = '$gid'"
echo "Full Name = '$name'"
echo "Home Dir = '$home'"
echo "Shell = '$shell'"vim read-ifs.sh
Notice that we set
IFS=":"
before callingread
. The shell allows one or more variable assignments to take place immediately before a command. These assignments alter the environment for the command that follows. The effect of the assignment is temporary changing the environment, for the duration of the command.It is the same as doing this, but more concise:
OLD_IFS="$IFS"
IFS=":"
read user pw uid gid name home shell <<< "$file_info"
IFS="$OLD_IFS"The
<<<
operator indicates a here string. A here string is like a here document, only shorter, consisting of a single string. We need to use it becauseread
does not work well with a pipe (for example:echo "$file_info" | read ...
)./read-ifs.sh # enter: xyz
./read-ifs.sh # enter: user1