As a system administrator or developer, directly interacting with the user via the command line is a common need. But bash doesn‘t include a built-in method for reading input. This is where the humble but powerful read command comes in handy.
Let‘s thoroughly explore how to leverage read to effortlessly collect user input in your bash scripts.
Why Read Over Other Input Methods
You may be wondering – why use read rather than other ways of getting input?
Bash does provide alternate options to retrieve data:
- Command arguments –
$1,$2etc access params given when invoking scripts - Command substitution – inline using
$(cmd)or backticks
However, read has distinct advantages:
- More flexible/interactive vs one-shot command args
- Avoids ugly nested command substitutions
- Stores input directly into clean variable names
- Additional options to control input behavior
- Portable across major shells like bash/zsh/ksh
For routine user input, read should be your first choice.
Read Command Syntax and Behavior
The basic syntax for read is straightforward:
read [options] [variable1] [variable2] ...
Without any arguments, read will retrieve input from standard input and store it in the special $REPLY variable.
For example:
read
echo "Input was: $REPLY"
$ ./script.sh
Hello world
Input was: Hello world
To save the input into a specific variable, just pass the variable name:
read myvar
echo "The value stored was: $myvar"
This makes collecting user input easy while keeping your code tidy.
By default word splitting is done on whitespace to allow handling multiple values.
Now let‘s look at some cases demonstrating the power of read.
Real-World Read Usage Examples
While the basics of read are simple, creative applications unlock additional capabilities:
Reading CSV Data into Variables
read neatly handles comma-separated values:
echo "Enter name,age,email"
read name age email
echo "$name is $age years old at $email"
It can also populate arrays:
read -a userData
echo "Name: ${userData[0]}"
echo "Email: ${userData[2]}"
Collecting Confirmation Prompts
Add an interactive confirmation with custom handling based on yes/no response:
read -p "Install package (y/n)? " confirm
if [[ "$confirm" =~ ^([yY][eE][sS]|[yY])$ ]]; then
echo "Installing ..."
else
echo "Installation cancelled"
exit
fi
Secure Password Entry
read makes this effortless whereas most other approaches print sensitive info:
read -sp "DB Password: " dbpass; echo
export DB_PASS=$dbpass
# use $DB_PASS
Building Interactive Menus
PS3="Choose an option: "
select opt in Install Remove Quit; do
case $opt in
Install)
installMenu
;;
Remove)
removeMenu
;;
Quit) break ;;
esac
done
Menus pair nicely with read for intuitive UIs.
Implementing Timeouts
Ever need the user to provide input within an allotted time window?
timeout=10
read -t $timeout -p "Enter something: "
if [[ $? -ne 0 ]]; then
echo "Too slow!"
fi
Reading Multiple Inputs
read can handle multiple inputs at once by specifying multiple variables:
read firstName lastName age
echo "$firstName $lastName is $age years old"
$ ./script.sh
John Doe 25
John Doe is 25 years old
The input is split on any whitespace by default. This behavior can be overridden but whitespace field splitting suits most use cases.
Useful Options
While the basics of read are straightforward, additional options unlock further capabilities:
Read Secret Input with -s
The -s flag prevents input from being visible as typed, useful for passwords:
read -sp "Enter DB password: " dbpass; echo
echo "Password set"
Similar behavior can be implemented manually but -s handles obscuring seamlessly.
Timeout Reading with -t
Ever need the user to respond within a time limit or you want to discard input after a window expires? The -t option sets a timeout in seconds:
read -t 5 -p "Enter your name: " name 2>&1 >/dev/null
[ $? -eq 0 ] && echo "Hello $name" || echo "Sorry, too slow!"
This even works without a variable to simply throw away unused input.
The examples show discarding stdin after a timeout occurs but timeout duration could be dynamically calculated as well.
Read Limited Input with -n
To have read return after an exact number of characters, use the -n option:
read -n1 -p "Press any key to continue..."
echo "Continuing..."
This allows simple single character input validation.
For example, vetting y/n input without needing pressing enter:
read -n1 -p "Install (y/n)? " ans
echo
if [[ $ans =~ [Yy] ]]; then
installPkg
fi
Disable Interpretation with -r
By default read will process certain escape sequences like \n or backslashes. The -r option disables this behavior to read raw input verbatim:
read -r input
echo "You entered: $input"
Read Array Input with -a
While read var1 var2 works for distinct variables, the -a option populates array data:
read -p "Enter codes: " -a codes
for n in ${codes[@]}; do
echo $n
done
Advanced Usage
While daily read usage may be simple, some advanced applications open further possibilities.
Process Substitution
Feed read using process substitution to act on transient files:
read line < <(grep pattern file.txt)
echo "Matching line: $line"
This temporary input stream is discarded when the subprocess completes.
Reading One Character at a Time
What if you need to process a stream one character instead of a line at a time?
By combining timeout and -n1 we can implement this:
while timeout 1 read -n1 -t1 char; do
process $char
done < input.txt
This shows how creatively composing options enables new use cases.
Non-Standard Input Sources
While read primarily sources from standard input, any file descriptor can be used:
exec 3< testfile
read line <&3
# read continues from fd 3
Stdin itself can even be redirected into read:
exec 0< testfile
read line # from redirected stdin
This flexibility supports read consuming content from sockets, pipes etc.
Piping Data into Read
Speaking of pipes, they integrate seamlessly with read to process command output:
ls -l /etc | while read line; do
echo "Got $line"
done
Here the ls output is iteratively piped into read.
Validating and Processing Input
Bash provides many built-in tools to validate or transform input collected by read.
For example, to ensure only a number within a range was entered:
read -p "Enter port [1-65535]: " port
if [[ ! $port =~ ^[0-9]+$ ]]; then
echo "Invalid format entered" >&2; exit 1
elif [[ $port -lt 1 || $port -gt 65535 ]]; then
echo "Out of range" >&2; exit 1
fi
echo "Using port $port"
We can leverage other utilities like awk, grep, sed etc. to process input as needed.
Ensuring Robust Scripts
While read is very convenient, some best practices should be followed:
- Always check return value from
readin case of errors - Handle EOF scenario if
readoutput is critical - Validate input data matches expected format/range
- Use whitespace delimiting correctly for multiple variables
- Avoid mixing options like
-tand-n
Issues may arise from unreliable input streams or users manually terminating scripts.
Planning for adverse situations will ensure your scripts don‘t crash unexpectedly.
Read Keeps You Ahead
Whether used for simple user prompts or complex input scenarios, read is a versatile bash built-in. I hope this deep dive has revealed fresh techniques on how to use read effectively.
The examples only scratch the surface – with bash‘s rich facilities for variables, flow control, subshells and streams the possibilities are endless!
Challenge yourself to experiment with read and see where it can simplify and enhance your shell scripts.


