Linux CLI 55 🐧 shell scripts output text
#!/bin/bash
# Simple echo command to output text
echo "Hello, World!"
greeting="Welcome to Shell Scripting"
echo $greeting
echo "This is a newline:\nAnd this is a tab:\t."
echo -n "Hello, "
echo "World!"
name="Alice"
age=30
printf "Name: %s\nAge: %d\n" "$name" "$age"
number=123.456789
printf "%.2f\n" "$number" # Output will be "123.46"
cat << EOF
This is a here document.
It can span multiple lines.
EOF
cat << EOF
Name: $name
Age: $age
EOF
Outputting text is the most basic thing a shell script does. You can use echo for simple messages, printf when you need precise formatting, and here documents when you need to pass a block of multi-line text to a command.
Key point: echo is quick and convenient but behaves differently across shells. printf is predictable and portable. Here documents let you feed multi-line input to any command without creating a temporary file.
a – echo in shell scripts
echo is the fundamental tool for outputting text or variables in shell scripting. It prints its arguments to standard output, separated by spaces, followed by a newline.
Basic usage:
$ echo "Hello, World!"
[ Hello, World! ]
$ greeting="Welcome to Shell Scripting"
$ echo $greeting
[ Welcome to Shell Scripting ]
Escape characters:
Use -e to enable escape sequence interpretation:
$ echo -e "This is a newline:\nAnd this is a tab:\t."
[ This is a newline:
And this is a tab: . ]
| Escape | Meaning |
|---|---|
\n | Newline |
\t | Tab |
\\ | Backslash |
\a | Alert (bell) |
\r | Carriage return |
\b | Backspace |
\c | Suppress trailing newline |
⚠️ Important: The
-eflag is not portable. Inbashandzshit works, but indash(the default/bin/shon Debian/Ubuntu)echointerprets escapes by default and-eprints a literal-e. For portable scripts, useprintfinstead.
The -n option — no trailing newline:
$ echo -n "Hello, "
$ echo "World!"
[ Hello, World! ]
Without -n, the two echo calls would print on separate lines:
$ echo "Hello, "
$ echo "World!"
[ Hello, ]
[ World! ]
Printing variables:
$ name="Alice"
$ echo "Hello, $name"
[ Hello, Alice ]
$ echo 'Hello, $name'
[ Hello, $name ]
Single quotes prevent expansion — $name is printed literally.
Common echo uses:
# Blank line
echo
# Message
echo "Starting backup..."
# Variable value
echo "$HOME"
# Command substitution
echo "Today is $(date +%F)"
# Multiple values
echo "Name:" "$name" "Age:" "$age"
[ Name: Alice Age: 30 ]
# Redirect to a file
echo "log entry" >> app.log
# Print to stderr
echo "Error: file not found" >&2
echo vs printf — when to use which:
| Aspect | echo | printf |
|---|---|---|
| Simplicity | Simple | More verbose |
| Portability | Shell-dependent | POSIX-standard |
| Escape handling | -e (bash), default (sh) | Explicit \n |
| Formatting | None | Width, precision, types |
| Newline | Automatic | Manual \n |
| Best for | Quick messages | Scripts, tables |
Rule of thumb: Use
echofor quick messages andprintffor anything that needs to be portable or formatted.
b – printf and here document in shell scripts
printf — precise control over output format:
printf gives you the same formatting power as C’s printf(). You provide a format string with specifiers, then the values to fill them.
$ name="Alice"
$ age=30
$ printf "Name: %s\nAge: %d\n" "$name" "$age"
[ Name: Alice ]
[ Age: 30 ]
Common format specifiers:
| Specifier | Purpose |
|---|---|
%s | String |
%d | Decimal integer |
%f | Float |
%x | Hexadecimal |
%o | Octal |
%c | Character |
%% | Literal % |
Width and precision:
$ number=123.456789
$ printf "%.2f\n" "$number"
[ 123.46 ]
$ printf "%10.2f\n" "$number"
[ 123.46 ]
$ printf "%-10s|\n" "left"
[ left | ]
$ printf "%05d\n" 42
[ 00042 ]
| Format | Meaning |
|---|---|
%.2f | 2 decimal places |
%10.2f | Width 10, 2 decimals |
%-10s | Left-align in 10 columns |
%05d | Zero-pad to 5 digits |
Building a table:
$ printf "%-10s %-5s\n" "NAME" "AGE"
$ printf "%-10s %-5d\n" "Alice" 30
$ printf "%-10s %-5d\n" "Bob" 25
[ NAME AGE ]
[ Alice 30 ]
[ Bob 25 ]
printf does not add a newline — you must include \n:
$ printf "Hello"
[ Hello ] $ # prompt on same line
$ printf "Hello\n"
[ Hello ]
$
printf vs echo for variables with special characters:
$ var="100% done"
$ echo "$var"
[ 100% done ]
$ printf "$var\n" # ❌ % is a format specifier!
[ 100 done ] # wait, actually this may error or misbehave
$ printf '%s\n' "$var" # ✅ safe — %s treats it literally
[ 100% done ]
⚠️ Warning: Never use a variable as the format string. Always use
printf '%s\n' "$var"to print variables safely.
Here documents — multi-line input:
A here document (heredoc) lets you pass a block of multi-line text to a command’s standard input, directly in the script. No temporary file needed.
Syntax:
command << DELIMITER
line 1
line 2
line 3
DELIMITER
The DELIMITER can be any word — EOF, END, STOP, etc. It must appear alone on a line to end the block.
Example 1 — multi-line text:
$ cat << EOF
This is a here document.
It can span multiple lines.
EOF
[ This is a here document. ]
[ It can span multiple lines. ]
Example 2 — using variables:
$ name="Alice"
$ age=30
$ cat << EOF
Name: $name
Age: $age
EOF
[ Name: Alice ]
[ Age: 30 ]
Variables are expanded inside the heredoc — because the delimiter is unquoted.
Quoting the delimiter — no expansion:
$ name="Alice"
$ cat << 'EOF'
Name: $name
Age: $age
EOF
[ Name: $name ]
[ Age: $age ]
With 'EOF' (quoted), variables are not expanded — the text is literal.
| Delimiter | Variable expansion |
|---|---|
<< EOF | Yes |
<< "EOF" | No |
<< 'EOF' | No |
<< \EOF | No |
Indented here documents with <<-:
Use <<- to allow leading tabs (not spaces) to be stripped:
$ cat <<- EOF
This line has a leading tab
So does this one
EOF
[ This line has a leading tab ]
[ So does this one ]
Common uses of here documents:
# Feed a multi-line SQL query to mysql
mysql -u root -p << EOF
SELECT * FROM users;
SELECT COUNT(*) FROM orders;
EOF
# Send an email body
mail -s "Report" admin@example.com << EOF
Here is the report for today.
All systems operational.
EOF
# Generate a config file
cat > /etc/myapp.conf << EOF
[server]
host = $HOSTNAME
port = 8080
[logging]
level = info
EOF
# Run a remote script over SSH
ssh user@host << EOF
cd /var/log
ls -lh
df -h
EOF
# Create a file with literal content
cat > script.sh << 'EOF'
#!/bin/bash
echo "Hello from a generated script"
EOF
chmod +x script.sh
Why here documents matter:
- Pass multi-line input without quoting hell
- No temporary files
- Variable expansion when you want it, literal text when you don’t
- Works with any command that reads stdin
Complete Example Session
# ============================================
# PART 1: BASIC ECHO
# ============================================
$ echo "Hello, World!"
[ Hello, World! ]
$ greeting="Welcome to Shell Scripting"
$ echo $greeting
[ Welcome to Shell Scripting ]
# ============================================
# PART 2: ECHO WITH ESCAPES
# ============================================
$ echo -e "This is a newline:\nAnd this is a tab:\t."
[ This is a newline:
And this is a tab: . ]
# ============================================
# PART 3: ECHO -N (NO NEWLINE)
# ============================================
$ echo -n "Hello, "
$ echo "World!"
[ Hello, World! ]
# ============================================
# PART 4: PRINTF
# ============================================
$ name="Alice"
$ age=30
$ printf "Name: %s\nAge: %d\n" "$name" "$age"
[ Name: Alice ]
[ Age: 30 ]
$ number=123.456789
$ printf "%.2f\n" "$number"
[ 123.46 ]
$ printf "%05d\n" 42
[ 00042 ]
$ printf "%-10s|\n" "left"
[ left | ]
# ============================================
# PART 5: PRINTF TABLE
# ============================================
$ printf "%-10s %-5s\n" "NAME" "AGE"
$ printf "%-10s %-5d\n" "Alice" 30
$ printf "%-10s %-5d\n" "Bob" 25
[ NAME AGE ]
[ Alice 30 ]
[ Bob 25 ]
# ============================================
# PART 6: HEREDOC — MULTI-LINE
# ============================================
$ cat << EOF
This is a here document.
It can span multiple lines.
EOF
[ This is a here document. ]
[ It can span multiple lines. ]
# ============================================
# PART 7: HEREDOC — WITH VARIABLES
# ============================================
$ name="Alice"
$ age=30
$ cat << EOF
Name: $name
Age: $age
EOF
[ Name: Alice ]
[ Age: 30 ]
# ============================================
# PART 8: HEREDOC — NO EXPANSION
# ============================================
$ cat << 'EOF'
Name: $name
Age: $age
EOF
[ Name: $name ]
[ Age: $age ]
# ============================================
# PART 9: HEREDOC — GENERATE A SCRIPT
# ============================================
$ cat > greet.sh << 'EOF'
#!/bin/bash
echo "Hello from a generated script"
EOF
$ chmod +x greet.sh
$ ./greet.sh
[ Hello from a generated script ]
# ============================================
# PART 10: HEREDOC — CONFIG FILE
# ============================================
$ cat > /tmp/myapp.conf << EOF
[server]
host = $HOSTNAME
port = 8080
[logging]
level = info
EOF
$ cat /tmp/myapp.conf
[ [server] ]
[ host = olympos ]
[ port = 8080 ]
[ ]
[ [logging] ]
[ level = info ]
# ============================================
# PART 11: HEREDOC — REMOTE COMMANDS
# ============================================
$ ssh user@host << EOF
cd /var/log
ls -lh
df -h
EOF
# ============================================
# PART 12: HEREDOC — SQL
# ============================================
$ mysql -u root -p << EOF
SELECT COUNT(*) FROM users;
SELECT * FROM orders WHERE total > 100;
EOF
Quick Reference
echo
| Command | Purpose |
|---|---|
echo "text" | Print text |
echo $VAR | Print variable |
echo | Print blank line |
echo -n "text" | No trailing newline |
echo -e "a\nb" | Interpret escapes |
echo "text" > file | Redirect to file |
echo "text" >> file | Append to file |
echo "error" >&2 | Print to stderr |
echo — Escapes (with -e)
| Escape | Meaning |
|---|---|
\n | Newline |
\t | Tab |
\\ | Backslash |
\a | Bell |
\r | Carriage return |
\b | Backspace |
\c | Suppress newline |
printf — Specifiers
| Specifier | Purpose |
|---|---|
%s | String |
%d | Integer |
%f | Float |
%x | Hex |
%o | Octal |
%c | Character |
%% | Literal % |
printf — Formatting
| Format | Meaning |
|---|---|
%.2f | 2 decimals |
%10.2f | Width 10, 2 decimals |
%-10s | Left-align width 10 |
%10s | Right-align width 10 |
%05d | Zero-pad to 5 |
%b | String with escapes |
Here Documents
| Syntax | Behavior |
|---|---|
<< EOF | Expand variables |
<< 'EOF' | No expansion |
<< "EOF" | No expansion |
<< \EOF | No expansion |
<<- EOF | Strip leading tabs |
echo vs printf vs heredoc
| Tool | Best for |
|---|---|
echo | Quick messages |
printf | Formatted output |
| heredoc | Multi-line input |
Best Practices
✅ Do This:
# Use printf in scripts for portability
printf "Name: %s\n" "$name" # ✅
# Always add \n with printf
printf "Hello\n" # ✅
# Use printf '%s\n' to print variables safely
printf '%s\n' "$var" # ✅
# Quote heredoc delimiter to prevent expansion
cat << 'EOF' # ✅
$literal text
EOF
# Use here documents for config generation
cat > config << EOF # ✅
host=$HOSTNAME
port=8080
EOF
# Use tabs with <<- for indented heredocs
cat <<- EOF # ✅
indented
EOF
# Redirect errors to stderr
echo "Error" >&2 # ✅
# Use echo for simple messages
echo "Done" # ✅
❌ Don’t Do This:
# Don't rely on echo -e being portable
echo -e "a\nb" # ⚠️ not in dash
# Don't forget \n with printf
printf "Hello" # ❌ no newline
# Don't pass a variable as printf format
printf "$var\n" # ❌ format injection
# Don't use unquoted delimiter when you want literal text
cat << EOF # ⚠️ expands variables
$literal
EOF
# Don't use spaces with <<- (only tabs)
cat <<- EOF # ❌ spaces not stripped
indented
EOF
# Don't forget the closing delimiter
cat << EOF # ❌ hangs waiting for EOF
some text
# Don't mix echo styles across shells
# Use printf for portable scripts # ✅
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
echo -e in dash | Prints literal -e | Use printf |
Missing \n in printf | No newline | Add \n |
| Variable as format | Format injection | Use %s |
| Heredoc expands vars | Unwanted expansion | Quote the delimiter |
<<- with spaces | Not stripped | Use tabs only |
| Unclosed heredoc | Script hangs | Add closing delimiter |
| Newline missing | Output runs together | Use echo or add \n |
| Binary output | Garbled | Use printf with care |
Real-World Examples
1. Simple Message
#!/bin/bash
echo "Hello, World!"
[ Hello, World! ]
2. Welcome Message
#!/bin/bash
greeting="Welcome to Shell Scripting"
echo $greeting
[ Welcome to Shell Scripting ]
3. Escape Characters
#!/bin/bash
echo -e "This is a newline:\nAnd this is a tab:\t."
[ This is a newline:
And this is a tab: . ]
4. No Newline
#!/bin/bash
echo -n "Hello, "
echo "World!"
[ Hello, World! ]
5. Formatted Output
#!/bin/bash
name="Alice"
age=30
printf "Name: %s\nAge: %d\n" "$name" "$age"
[ Name: Alice ]
[ Age: 30 ]
6. Float Precision
#!/bin/bash
number=123.456789
printf "%.2f\n" "$number"
[ 123.46 ]
7. Zero-Padded Numbers
#!/bin/bash
for i in 1 2 3; do
printf "%03d\n" "$i"
done
[ 001 ]
[ 002 ]
[ 003 ]
8. Aligned Table
#!/bin/bash
printf "%-15s %-10s %5s\n" "NAME" "DEPT" "SCORE"
printf "%-15s %-10s %5d\n" "Alice" "Eng" 95
printf "%-15s %-10s %5d\n" "Bob" "Math" 87
[ NAME DEPT SCORE ]
[ Alice Eng 95 ]
[ Bob Math 87 ]
9. Multi-Line Heredoc
#!/bin/bash
cat << EOF
This is a here document.
It can span multiple lines.
EOF
[ This is a here document. ]
[ It can span multiple lines. ]
10. Heredoc with Variables
#!/bin/bash
name="Alice"
age=30
cat << EOF
Name: $name
Age: $age
EOF
[ Name: Alice ]
[ Age: 30 ]
11. Literal Heredoc
#!/bin/bash
cat << 'EOF'
Name: $name
Age: $age
EOF
[ Name: $name ]
[ Age: $age ]
12. Generate a Config File
#!/bin/bash
cat > /etc/myapp.conf << EOF
[server]
host = $HOSTNAME
port = 8080
[logging]
level = info
EOF
echo "Config written"
[ Config written ]
13. Generate a Script
#!/bin/bash
cat > backup.sh << 'EOF'
#!/bin/bash
tar -czf /backup/home-$(date +%F).tar.gz /home
EOF
chmod +x backup.sh
echo "Backup script created"
[ Backup script created ]
14. Send an Email
#!/bin/bash
mail -s "Daily Report" admin@example.com << EOF
Report for $(date +%F)
System: $HOSTNAME
Uptime: $(uptime -p)
Disk: $(df -h / | tail -1)
EOF
15. SQL Query
#!/bin/bash
mysql -u root -p << EOF
SELECT COUNT(*) FROM users;
SELECT * FROM orders WHERE total > 100;
EOF
16. Remote Commands over SSH
#!/bin/bash
ssh user@host << EOF
cd /var/log
ls -lh
df -h
EOF
17. Indented Heredoc
#!/bin/bash
if true; then
cat <<- EOF
This is indented in the script
but not in the output.
EOF
fi
[ This is indented in the script ]
[ but not in the output. ]
18. Progress with printf
#!/bin/bash
for i in $(seq 1 100); do
printf "\rProgress: %3d%%" "$i"
sleep 0.01
done
echo
[ Progress: 100% ]
19. Colored Output
#!/bin/bash
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'
echo -e "${RED}Error:${NC} something failed"
echo -e "${GREEN}Success:${NC} all done"
[ Error: something failed ]
[ Success: all done ]
20. Log with Timestamps
#!/bin/bash
log() {
printf "[%s] %s\n" "$(date +%F' '%T)" "$1"
}
log "Starting backup"
log "Backup complete"
[ [2024-01-15 10:00:00] Starting backup ]
[ [2024-01-15 10:00:00] Backup complete ]
Visual: echo vs printf vs heredoc
┌──────────────────────────────────────────────┐
│ echo │
│ │
│ echo "Hello" │
│ → [ Hello ] │
│ │
│ • Quick, simple │
│ • Adds newline automatically │
│ • Escape handling varies by shell │
│ │
└──────────────────────────────────────────────┘
┌──────────────────────────────────────────────┐
│ printf │
│ │
│ printf "Name: %s\n" "Alice" │
│ → [ Name: Alice ] │
│ │
│ • Precise formatting │
│ • No automatic newline │
│ • Portable — same everywhere │
│ • Width, precision, types │
│ │
└──────────────────────────────────────────────┘
┌──────────────────────────────────────────────┐
│ here document │
│ │
│ cat << EOF │
│ Line 1 │
│ Line 2 │
│ EOF │
│ → [ Line 1 ] │
│ → [ Line 2 ] │
│ │
│ • Multi-line input │
│ • No temp files │
│ • Optional variable expansion │
│ │
└──────────────────────────────────────────────┘
Summary
| Command | Purpose | Example |
|---|---|---|
echo "text" | Print text | echo "Hello" |
echo $VAR | Print variable | echo $name |
echo -n | No newline | echo -n "Hi " |
echo -e | Interpret escapes | echo -e "a\nb" |
printf "%s" | Formatted string | printf "%s\n" "$name" |
printf "%d" | Integer | printf "%d\n" 42 |
printf "%.2f" | Float precision | printf "%.2f\n" 3.14 |
printf "%-10s" | Left-align | printf "%-10s|\n" "x" |
printf "%05d" | Zero-pad | printf "%05d\n" 42 |
cat << EOF | Heredoc | cat << EOF ... EOF |
cat << 'EOF' | Literal heredoc | No variable expansion |
cat <<- EOF | Strip tabs | Indented heredoc |
cmd << EOF | Feed stdin | mysql << EOF ... EOF |
cat > file << EOF | Write file | Generate config |
Key takeaways:
echois quick and simple — use it for short messagesecho -einterprets escapes but is not portable — useprintfin scriptsecho -nsuppresses the trailing newlineprintfgives you precise control — width, precision, typesprintfdoes not add a newline — include\nyourself- Use
printf '%s\n' "$var"to safely print variables that may contain% - Here documents let you feed multi-line input to any command
- Use
<< EOFto allow variable expansion,<< 'EOF'to prevent it - Use
<<- EOFto strip leading tabs (not spaces) - Here documents are perfect for generating configs, scripts, SQL, and emails
- Combine
printfwithechoand heredocs for full control over output
Remember: echo for quick, printf for precise, heredocs for multi-line. In scripts, prefer printf — it’s portable and predictable. Watch out for echo -e in dash. Always add \n with printf. Quote your heredoc delimiter when you want literal text. And use heredocs whenever you need to feed a block of text to a command — they’re cleaner than echo chains and safer than temp files.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!