Input/Output¶
Reading input and producing formatted output in bash scripts.
Reading Input¶
The read Command¶
User types input, stored in variable:
Prompt with -p¶
Silent Input with -s¶
For passwords:
read -sp "Password: " password
echo # Newline after hidden input
echo "Password has ${#password} characters"
Timeout with -t¶
if read -t 5 -p "Quick! Enter something: " answer; then
echo "You entered: $answer"
else
echo "Too slow!"
fi
Default Value¶
Limit Characters with -n¶
Read Array with -a¶
Read with Delimiter -d¶
Common Options¶
| Option | Purpose |
|---|---|
-p prompt | Display prompt |
-s | Silent (no echo) |
-t seconds | Timeout |
-n count | Read count characters |
-r | Raw (don't interpret backslashes) |
-a array | Read into array |
-d delim | Use delimiter instead of newline |
Reading Files¶
Line by Line¶
Components:
IFS=- Don't trim whitespace-r- Don't interpret backslashes< file.txt- Input from file
Read Specific Fields¶
# /etc/passwd: user:x:uid:gid:desc:home:shell
while IFS=: read -r user _ uid gid _ home shell; do
echo "$user (UID: $uid) -> $shell"
done < /etc/passwd
Read from Command Output¶
Read from Here Document¶
while IFS= read -r line; do
echo "Config: $line"
done << 'EOF'
setting1=value1
setting2=value2
setting3=value3
EOF
Basic Output¶
echo¶
echo "Hello, World!"
echo -n "No newline" # No trailing newline
echo -e "Tab:\tNewline:\nDone" # Interpret escapes
Echo escapes (with -e):
| Escape | Meaning |
|---|---|
\n | Newline |
\t | Tab |
\r | Carriage return |
\\ | Backslash |
\033[...m | ANSI color codes |
printf¶
More control over formatting:
printf "Hello, %s!\n" "World"
printf "Number: %d\n" 42
printf "Float: %.2f\n" 3.14159
printf "Hex: %x\n" 255
Format specifiers:
| Specifier | Type |
|---|---|
%s | String |
%d or %i | Integer |
%f | Float |
%e | Scientific notation |
%x / %X | Hexadecimal |
%o | Octal |
%% | Literal % |
printf Width and Alignment¶
| Format | Meaning |
|---|---|
%10s | Right-aligned, width 10 |
%-10s | Left-aligned, width 10 |
%05d | Zero-padded, width 5 |
%.2f | 2 decimal places |
%10.2f | Width 10, 2 decimals |
printf to Variable¶
Here Documents¶
Multi-line input:
Variable Expansion¶
No Expansion (Quoted Delimiter)¶
Indented (Tab Removal)¶
Tabs Only
The <<- syntax only strips tabs, not spaces.
Here Document to Command¶
Here Document to Variable¶
Here Strings¶
Single-line input:
grep "pattern" <<< "search in this string"
# Equivalent to:
echo "search in this string" | grep "pattern"
Colored Output¶
Basic ANSI Colors¶
# Colors
RED='\033[31m'
GREEN='\033[32m'
YELLOW='\033[33m'
BLUE='\033[34m'
RESET='\033[0m'
echo -e "${RED}Error${RESET}: Something failed"
echo -e "${GREEN}Success${RESET}: All good"
printf "${YELLOW}Warning${RESET}: Be careful\n"
tput for Portable Colors¶
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
BOLD=$(tput bold)
RESET=$(tput sgr0)
echo "${RED}Error${RESET}"
echo "${BOLD}${GREEN}Success${RESET}"
Color Functions¶
red() { printf '\033[31m%s\033[0m\n' "$*"; }
green() { printf '\033[32m%s\033[0m\n' "$*"; }
yellow() { printf '\033[33m%s\033[0m\n' "$*"; }
blue() { printf '\033[34m%s\033[0m\n' "$*"; }
error() { red "Error: $*" >&2; }
success() { green "Success: $*"; }
warn() { yellow "Warning: $*"; }
info() { blue "Info: $*"; }
Check for Color Support¶
if [[ -t 1 ]] && [[ -n "$TERM" ]] && [[ "$TERM" != "dumb" ]]; then
# Terminal supports colors
RED='\033[31m'
RESET='\033[0m'
else
RED=''
RESET=''
fi
Progress Indicators¶
Simple Counter¶
Percentage¶
total=100
for ((i=1; i<=total; i++)); do
percent=$((i * 100 / total))
printf "\r[%-50s] %d%%" $(printf '#%.0s' $(seq 1 $((i/2)))) "$percent"
sleep 0.05
done
echo
Spinner¶
spinner() {
local pid=$1
local spin='-\|/'
local i=0
while kill -0 "$pid" 2>/dev/null; do
printf "\r[%c] Working..." "${spin:i++%4:1}"
sleep 0.1
done
printf "\rDone! \n"
}
# Usage
sleep 3 &
spinner $!
Output Formatting¶
Tables¶
# Header
printf "%-15s %-10s %10s\n" "Name" "Status" "Count"
printf "%-15s %-10s %10s\n" "---------------" "----------" "----------"
# Data
printf "%-15s %-10s %10d\n" "Service A" "Running" 42
printf "%-15s %-10s %10d\n" "Service B" "Stopped" 0
printf "%-15s %-10s %10d\n" "Service C" "Running" 123
Name Status Count
--------------- ---------- ----------
Service A Running 42
Service B Stopped 0
Service C Running 123
Column Command¶
Logging Functions¶
#!/usr/bin/env bash
LOG_LEVEL="${LOG_LEVEL:-INFO}"
log() {
local level="$1"
shift
local timestamp
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
printf "[%s] %-5s %s\n" "$timestamp" "$level" "$*"
}
debug() { [[ "$LOG_LEVEL" == "DEBUG" ]] && log "DEBUG" "$@"; }
info() { log "INFO" "$@"; }
warn() { log "WARN" "$@" >&2; }
error() { log "ERROR" "$@" >&2; }
fatal() { log "FATAL" "$@" >&2; exit 1; }
# Usage
info "Starting script"
debug "Debug message (only if LOG_LEVEL=DEBUG)"
warn "This is a warning"
error "This is an error"
Try It¶
-
Read input:
-
Formatted output:
-
Read file:
-
Here document:
-
Colored output:
Summary¶
| Task | Command |
|---|---|
| Read line | read var |
| Read with prompt | read -p "Prompt: " var |
| Silent input | read -s var |
| Read file | while read -r line; do ... done < file |
| Print string | echo "text" or printf "text\n" |
| Formatted print | printf "%s %d\n" str num |
| Here document | cat << EOF ... EOF |
| Here string | cmd <<< "string" |
Best practices:
- Use
read -rto prevent backslash interpretation - Use
IFS=when reading to preserve whitespace - Prefer
printfoverechofor portability - Quote here document delimiter to prevent expansion
- Use functions for colored/logging output