The bash read command to get user input with examples is something every Linux user eventually needs to understand. If you want your shell script to interact with users by asking for their names, passwords, or even simple yes/no confirmations, then the read command will be your best friend. Unlike some other commands, read is built into Bash, so there's no cost to learning it. Once you learn how to use it correctly, you can turn your scripts from single-use applications into truly interactive tools.
Why This Matters Before You Start:
Most articles online only show you the basic read name syntax and call it a day. But in real Linux work, you will run into problems that nobody warns you about:
- Your script skips the
readprompt entirely when run via cron or a pipe - You forget to reset
IFSand it breaks the rest of your script - The
-ttimeout works differently inside a script vs on the terminal - Your
read -spassword field still echoes on some terminals
This guide covers all of that plus distro-specific differences, real DevOps examples, and a full cheat sheet nobody else has put together.
If you are just getting started with shell scripting, it helps to understand how bash itself works before diving into input handling. Check out this guide on what bash scripting is and how it works on Linux to get your footing first.
What Is the read Command and How Does It Work
The read command is a bash built-in that pauses script execution and waits for the user to type something. Whatever the user types gets stored in a variable that you can use later in the script. It is the core tool for making any interactive bash script work properly.
Here is the simplest form storing a name the user types:
LinuxTeck.com
read name
echo "Hello, $name"
Hello, John
The script pauses on the read name line. The user types "John" and hits Enter. The value gets stored in $name and echo prints it back. That is the full flow.
Important - Shebang Line Matters:
Always start your script with #!/bin/bash and not #!/bin/sh. On Ubuntu, /bin/sh points to dash, not bash. The read options like -e and -i are bash-only and will fail silently or throw errors under dash. On Rocky Linux and RHEL, /bin/sh usually points to bash, but it is still better to be explicit. The bash PATH and command lookup guide on LinuxTeck explains how Linux finds the right interpreter.
Bash read Command to Get User Input - All Options With Examples
This is the section nobody else has done properly. Below is every useful flag for the read command options in bash, each with a working example and a plain explanation of what it actually does.
The -p Flag Show a Prompt
Instead of printing a message with echo and then calling read, use -p to do both in one line:
LinuxTeck.com
read -p "Enter your username: " username
echo "Welcome, $username"
Welcome, alice
The -s Flag - Silent Input for Passwords
The -s flag hides the characters the user types. Combine with -p to prompt and hide in the same line:
LinuxTeck.com
read -sp "Enter password: " password
echo -e "\nPassword stored."
Common Mistake:
Using read -s inside a subshell or over SSH with a pseudo-terminal can still show typed characters on some setups. This is a terminal emulator issue, not a bash bug. Always test password prompts over SSH if that is your target environment.
The -t Flag Timeout
Set a time limit in seconds. If the user does not respond, read returns a non-zero exit code and the script moves on:
LinuxTeck.com
if read -t 10 -p "Continue? [y/n]: " answer; then
echo "You chose: $answer"
else
echo "Timed out. Using default."
fi
Common Mistake:
The -t flag only works when bash is reading from a terminal. If your script gets its input from a pipe or a file, -t is ignored on some bash versions. Always use a default fallback with an else block when using timeouts.
The -n Flag Limit Input Characters
Stops reading after a set number of characters no need for the user to press Enter:
LinuxTeck.com
read -n 1 -p "Press y to confirm, n to cancel: " choice
echo
echo "You pressed: $choice"
The -a Flag Read Into an Array
Each space-separated word goes into a separate array element:
LinuxTeck.com
read -a servers -p "Enter three server names: "
echo "First: ${servers[0]}"
echo "Second: ${servers[1]}"
echo "Third: ${servers[2]}"
First: web01
Second: web02
Third: db01
The -r Flag Raw Input
By default, bash treats backslash as an escape character in input. The -r flag disables that and treats every character literally. Use it almost always when reading file paths:
LinuxTeck.com
read -r -p "Enter full path: " filepath
echo "Path: $filepath"
Using IFS to Change the Delimiter
By default, read splits input on spaces. Change IFS (Internal Field Separator) to split on commas, colons, or any other character. Always restore IFS after use:
LinuxTeck.com
OLD_IFS="$IFS"
IFS="," read -r -p "Enter name,age,city: " name age city
IFS="$OLD_IFS"
echo "Name: $name | Age: $age | City: $city"
Name: Alice | Age: 30 | City: Berlin
Common Mistake Forgetting to Reset IFS:
If you set IFS="," globally and forget to restore it, every loop, word split, and field separator operation in the rest of your script will break in unexpected ways. Always save the old value first and restore it right after, or scope it inline on the same line as read as shown above.
Full read Command Flags Quick Reference Table
| Flag | Syntax Example | What It Does |
|---|---|---|
-p |
read -p "Label: " var |
Display a prompt string before waiting for input |
-s |
read -s -p "Pass: " pw |
Silent mode hides typed characters (for passwords) |
-t N |
read -t 10 -p "..." var |
Timeout after N seconds; returns non-zero exit code |
-n N |
read -n 1 -p "..." var |
Read exactly N characters, no Enter needed |
-r |
read -r var |
Raw mode backslashes are literal, not escape chars |
-a |
read -a arr |
Store space-separated words into an indexed array |
-d CHAR |
read -d ":" var |
Stop reading at a custom delimiter instead of newline |
-e |
read -e -p "..." var |
Enable readline editing (arrow keys, history) bash only |
-i TEXT |
read -e -i "default" -p "..." var |
Pre-fill input with a default value (requires -e) |
-u FD |
read -u 3 var |
Read from file descriptor FD instead of stdin |
IFS=X |
IFS="," read -r a b c |
Change field separator for this read call only |
Input Validation With Loops and Regex
When writing real shell scripts, handling bad input is just as important as handling good input. If a user types something wrong, your script should ask again not crash or silently continue with invalid data. The cleanest way to do that in bash is to wrap your read call inside a while loop and only break out once the input passes your check.
Validate Non-Empty Input
LinuxTeck.com
while true; do
read -r -p "Enter your name (cannot be empty): " username
if [[ -n "$username" ]]; then
break
fi
echo "Name cannot be empty. Try again."
done
echo "Hello, $username"
Validate a Number Using Regex
LinuxTeck.com
while true; do
read -r -p "Enter a port number (1-65535): " port
if [[ "$port" =~ ^[0-9]+$ ]] && (( port >= 1 && port
Invalid port. Enter a number between 1 and 65535.
Enter a port number (1-65535): 99999
Invalid port. Enter a number between 1 and 65535.
Enter a port number (1-65535): 8080
Port set to: 8080
Set a Default Value if the User Just Presses Enter
LinuxTeck.com
read -r -p "Enter environment [default: staging]: " env
env=${env:-staging}
echo "Deploying to: $env"
Deploying to: staging
Tip Default Values Pattern:
The ${var:-default} syntax is a bash parameter expansion that returns the default when $var is empty or unset. It does not change the stored value. To also assign the default use ${var:=default}. The Linux shell scripting command cheat sheet on LinuxTeck has more of these patterns in one place.
Interactive Bash Script With select Menu
Most tutorials never mention the select statement, which is a big oversight. When you want to give users a numbered list of choices, select is far cleaner than building your own menu with read and case manually. This is the backbone of a proper interactive bash script with select menu.
LinuxTeck.com
PS3="Choose your Linux distro: "
options=("Ubuntu" "Rocky Linux" "Debian" "Fedora" "Quit")
select opt in "${options[@]}"; do
case $opt in
"Ubuntu")
echo "You selected Ubuntu."
break ;;
"Rocky Linux")
echo "You selected Rocky Linux."
break ;;
"Debian")
echo "You selected Debian."
break ;;
"Fedora")
echo "You selected Fedora."
break ;;
"Quit")
echo "Exiting."
break ;;
*)
echo "Invalid option $REPLY. Try again." ;;
esac
done
2) Rocky Linux
3) Debian
4) Fedora
5) Quit
Choose your Linux distro: 2
You selected Rocky Linux.
Tip PS3 Variable:
The PS3 variable controls the prompt that select shows before each input. If you do not set it, bash defaults to #? which looks confusing to users. Always set a clear PS3 before your select loop. The variable $REPLY holds the raw number the user typed, while $opt holds the matched string from the list.
Real-World DevOps Script Examples
These are the kinds of scripts you actually use on the job. No other article on this topic covers these use cases. Each one is a working template you can copy and adapt right away.
Example 1 Deployment Confirmation Script
Before pushing anything to production, you want a hard stop that forces the user to explicitly confirm. Here is the pattern most DevOps teams use:
LinuxTeck.com
ENV="production"
read -r -p "You are about to deploy to $ENV. Are you sure? [y/N]: " confirm
confirm=${confirm:-N}
if [[ "$confirm" =~ ^[Yy]$ ]]; then
echo "Deployment started..."
# your deploy commands go here
else
echo "Deployment cancelled."
exit 0
fi
Example 2 Backup Script With User-Selected Destination
A script that asks the user to pick a backup destination from a menu, then confirms before running:
LinuxTeck.com
SOURCE="/var/www/html"
PS3="Select backup destination: "
destinations=("/mnt/backup" "/tmp/backup" "/home/admin/backup" "Quit")
select dest in "${destinations[@]}"; do
case $dest in
"Quit") echo "Cancelled."; exit 0 ;;
"") echo "Invalid choice." ;;
*)
read -r -p "Back up $SOURCE to $dest? [y/N]: " ok
ok=${ok:-N}
if [[ "$ok" =~ ^[Yy]$ ]]; then
echo "Running backup..."
rsync -av "$SOURCE" "$dest"
else
echo "Backup cancelled."
fi
break ;;
esac
done
Tip Backup Scripts in Production:
For server-level backups you need more than a simple script. The Linux server backup solutions guide on LinuxTeck covers tools and strategies used in real enterprise environments.
Example 3 mapfile and readarray for Reading Files Into Arrays
The mapfile (also called readarray) reads lines from a file or command output directly into a bash array - no manual loops required:
LinuxTeck.com
# Read /etc/hosts lines into array, skip comments
mapfile -t hosts_lines < /etc/hosts
for line in "${hosts_lines[@]}"; do
[[ "$line" == "#"* ]] && continue
echo "Line: $line"
done
You can also capture command output into an array using process substitution:
LinuxTeck.com
mapfile -t running_services < <(systemctl list-units --type=service --state=running --no-legend | awk '{print $1}')
echo "Running services: ${#running_services[@]}"
for svc in "${running_services[@]:0:5}"; do
echo " $svc"
done
Common Mistake Pipe and Subshell Issue:
You cannot do command | mapfile -t arr directly because the pipe creates a subshell and the array will not be visible in the parent shell. Always use process substitution < <(command) as shown above to keep the array in the current shell context.
Troubleshooting - Why read Is Not Working
Troubleshooting section on the read command. These are real problems you will face on the job, and here is how to fix each one.
Problem 1 read Skips Input When Script Is Called from a Pipe
If you run something like cat setup.sh | bash, the script's stdin is already occupied by the pipe. The read command immediately gets EOF and moves on without waiting. The fix is to read explicitly from the terminal:
LinuxTeck.com
# Read directly from the terminal even when stdin is piped
read -r -p "Enter your choice: " choice < /dev/tty
echo "Choice: $choice"
Problem 2 read Does Not Wait for Input in Cron Jobs
Cron runs scripts in a non-interactive shell with no terminal attached. Any read in a cron job will return immediately with an empty value. There is no fix for this read is not meant for unattended scripts. Move interactive prompts out of cron and pass values as script arguments instead:
LinuxTeck.com
# Cron-safe: accept input as arguments, not read prompts
ENV=${1:-staging}
echo "Running backup for environment: $ENV"
For more on scheduling and cron setup see the cron command guide with examples on LinuxTeck.
Problem 3 IFS Not Reset After Use
If you set IFS globally and forget to restore it, word splitting breaks everywhere downstream. Always save and restore:
LinuxTeck.com
# Safe IFS usage - save, use, restore
OLD_IFS="$IFS"
IFS=":" read -r user pass uid gid info home shell <<< "$(grep "^root" /etc/passwd)"
IFS="$OLD_IFS"
echo "Shell: $shell"
Problem 4 Distro-Specific Behavior Differences
| Distro | Default /bin/sh | read -e / -i support | Notes |
|---|---|---|---|
| Ubuntu 22.04 / 24.04 | dash | No (bash-only flags) | Always use #!/bin/bash; dash ignores -e and -i |
| Rocky Linux 8 / 9 | bash | Yes | Safe to use all flags; bash 5.x is default |
| RHEL 8 / 9 | bash | Yes | Same as Rocky; enterprise bash 5.x |
| Alpine Linux | busybox ash | No | Most bash-only flags fail; use POSIX-only read syntax |
| Debian 12 | dash | No | Same as Ubuntu; always specify #!/bin/bash |
Tip Comparing RHEL and Ubuntu for Server Use:
If you are deciding which distro to standardize on for your scripts, the RHEL vs Ubuntu Server comparison on LinuxTeck covers key differences including shell environments and scripting compatibility.
Problem 5 read With Pipes and Here-Strings
A common beginner trap is piping directly into read. The variable gets set inside a subshell and disappears when the pipe ends. Use a here-string instead:
LinuxTeck.com
# WRONG: variable lost after pipe
echo "hello world" | read word1 word2
echo $word1 # empty!
# CORRECT: use here-string
read word1 word2 <<< "hello world"
echo $word1 # hello
Frequently Asked Questions
How do I read multiple inputs in a single line bash?
List multiple variable names after read and bash will assign each space-separated word to each variable in order. The last variable gets everything that is left over.
LinuxTeck.com
echo "$first $last -- $email"
If you need a custom separator like a comma, set IFS before the read call and restore it right after. See Section 02 for the safe IFS pattern.
Why is bash read command not waiting for input?
The three most common reasons are:
- Script is being piped stdin is already occupied. Fix: redirect from
/dev/ttyas shown in Section 06. - Running in cron or CI/CD no terminal is attached.
readinstantly returns empty. Remove interactive prompts from any unattended execution paths. - Using
#!/bin/shon Ubuntu somereadflags do not exist in dash and the command behaves differently. Switch to#!/bin/bash.
For more on shell scripting error patterns see the bash exit codes and error handling guide on LinuxTeck.
How do I set a default value if the user just presses Enter?
Use bash parameter expansion right after the read call:
LinuxTeck.com
branch=${branch:-main}
echo "Using branch: $branch"
Alternatively use read -e -i "main" to pre-fill the input field bash only, not supported in dash.
Why does read -s still show input on some terminals?
The -s flag disables terminal echo via an ioctl call to the tty. If you are accessing the script over SSH without a pseudo-terminal (ssh -T), or if the terminal emulator overrides echo settings, the suppression may not work. Test with a real SSH session using a proper PTY. For production password handling consider using sudo with sudoers config or environment secrets rather than relying on read -s alone.
Can I use read in a cron job?
No, and you should not try. Cron jobs run without a terminal so read returns immediately with an empty value. Scripts that run unattended should accept configuration via arguments ($1, $2) or environment variables instead of interactive prompts. The cron command guide on LinuxTeck walks through the full scheduling setup.
How do I read input from a file instead of a user?
Redirect a file into a while loop using read to process it line by line:
LinuxTeck.com
# Process each line in servers.txt
while IFS= read -r line; do
echo "Connecting to: $line"
done < servers.txt
The IFS= before read prevents leading and trailing whitespace from being trimmed on each line. This is the canonical safe pattern for reading files in bash.
Summary
The bash read command to get user input with examples is more capable than most people realize. Beyond the basic -p and -s flags, you have a full toolkit for building interactive, validated, and menu-driven scripts that work reliably across Ubuntu, Rocky Linux, and RHEL.
The main things to remember: always use #!/bin/bash as your shebang, pair read with validation loops in production scripts, always restore IFS after changing it, and keep interactive prompts out of any script running in cron or CI/CD.
For a deeper look at scripting automation patterns used in real Linux environments, the Linux bash scripting automation guide on LinuxTeck is a solid next step.
🔗 Related Articles
Learn step-by-step how to automate Linux tasks with real-world scripts and practical examples.