- Overview
- Variable Notation
- Step 1: Metacharacters
- Step 2: Special Variables
- Step 3: Parameter Expansion
- Step 4: Arrays and Associative Arrays
- Step 5: Arithmetic Expansion
- Step 6: Conditions and Comparisons
- Step 7: Command Substitution and Subshells
- Step 8: Redirection and File Descriptors
- Step 9: Traps and Error Handling
- Step 10: Job Control
- Step 11: Reserved Commands
- Summary
Overview
This article provides a comprehensive summary of all special syntax, variables, expansion rules, and control structures used in Bash shell scripting.
Variable Notation
Dynamic or environment-dependent values are denoted as <<variable>>.
All examples below explicitly show their usage.
| Variable | Example | Description |
|---|---|---|
<<var>> |
name, path, user |
Arbitrary variable name |
<<default>> |
guest, 8080 |
Default or fallback value |
<<pattern>> |
*.txt, */ |
File or string pattern |
<<offset>> |
0, 3 |
Starting index of substring (0-based) |
<<length>> |
4, 10 |
Length of substring |
<<prefix>> |
ENV_, HOST |
Prefix pattern for variable names |
<<index>> |
0, 1, 2 |
Array or associative key index |
<<file>> |
/tmp/test.txt |
File path |
Step 1: Metacharacters
| Symbol | Meaning | Example |
|---|---|---|
* |
Matches any string | ls *.txt → lists all .txt files |
? |
Matches any single character | ls ?.sh → matches a.sh, b.sh |
[a-z] |
Range match | ls [A-Z]* → files starting with uppercase |
{a,b} |
Brace expansion | mv {hoge,huga} |
{1..3} |
Sequence expansion | touch file{1..3}.txt |
$ |
Variable expansion | echo $HOME |
! (negation) |
Logical NOT | [[ ! -f test.txt ]] |
! (history) |
History expansion | !10 → reruns command #10 |
~ |
Home directory | cd ~ |
; |
Command separator | pwd; ls |
&& |
Execute if previous succeeded | make && echo OK |
| ` | ` | |
& |
Run in background | sleep 5 & |
| ` | ` | Pipe output |
> |
Redirect stdout | echo hi > out.txt |
>> |
Append output | echo hi >> out.txt |
< |
Redirect stdin | wc -l < file.txt |
() |
Subshell | (cd /tmp; ls) |
{} |
Same shell block | { echo A; echo B; } |
\ |
Escape character | echo \$HOME |
' ' |
Literal (no expansion) | echo '$USER' |
" " |
Expand variables | echo "$USER" |
Step 2: Special Variables
| Variable | Description | Example |
|---|---|---|
$0 |
Script name | echo $0 → script.sh |
$1–$9 |
Positional args | echo $1 |
$@ |
All args as array | for a in "$@"; do echo $a; done |
$# |
Arg count | echo $# |
$? |
Last exit status | ls /nope; echo $? |
$$ |
Current PID | echo $$ |
$! |
Last BG job PID | sleep 10 & echo $! |
$- |
Current shell options | echo $- |
$_ |
Last arg of previous cmd | echo $_ |
$PPID |
Parent PID | echo $PPID |
$RANDOM |
Random number | echo $RANDOM |
$SECONDS |
Seconds since shell start | echo $SECONDS |
$FUNCNAME |
Function name | f(){ echo $FUNCNAME; }; f |
$PIPESTATUS[@] |
Exit status of pipe cmds | `ls |
Step 3: Parameter Expansion
| Syntax | Description | Example |
|---|---|---|
${<<var>>} |
Variable expansion | name=user; echo ${name} |
${<<var>>:-<<default>>} |
Use default if unset | echo ${user:-guest} |
${<<var>>:=<<default>>} |
Assign default if unset | echo ${port:=8080} |
${<<var>>:+alt} |
Use alt if set | x=1; echo ${x:+OK} |
${<<var>>:?msg} |
Error if unset | echo ${config:?missing} |
${#<<var>>} |
String length | name=user; echo ${#name} |
${<<var>>%<<pattern>>} |
Remove shortest suffix | path=/a/b/c; echo ${path%/*} |
${<<var>>%%<<pattern>>} |
Remove longest suffix | echo ${path%%/*} |
${<<var>>#<<pattern>>} |
Remove shortest prefix | echo ${path#*/} |
${<<var>>##<<pattern>>} |
Remove longest prefix | echo ${path##*/} |
${<<var>>/<<pattern>>/<<repl>>} |
Replace first match | echo ${msg/foo/bar} |
${<<var>>//<<pattern>>/<<repl>>} |
Replace all | echo ${msg// /_} |
${<<var>>:<<offset>>} |
Substring from offset | s=abcdef; echo ${s:2} |
${<<var>>:<<offset>>:<<length>>} |
Substring with length | echo ${s:1:3} |
${!<<prefix>>*} |
Vars with prefix | HOST1=x; HOST2=y; echo ${!HOST*} |
${!<<var>>} |
Indirect reference | ref=NAME; NAME=user; echo ${!ref} |
${<<var>>,} / ${<<var>>^^} |
Case conversion | n=abc; echo ${n^^} |
${<<var>>@Q} |
Quoted form | x='abc'; echo ${x@Q} |
Step 4: Arrays and Associative Arrays
arr=(a b c)
echo ${arr[<<index>>]} # Access element
echo ${#arr[@]} # Count
for i in "${arr[@]}"; do echo $i; done
declare -A map
map[<<index>>]=100
map[name]=user
echo ${map[<<index>>]} # Value
echo ${!map[@]} # Keys
Step 5: Arithmetic Expansion
x=5; y=3
echo $((x + y)) # 8
((x *= 2))
echo $x # 10
Step 6: Conditions and Comparisons
if [ "$USER" = "root" ]; then echo root; fi
if [ "$x" -lt 10 ]; then echo small; fi
if [ -f /etc/passwd ]; then echo exists; fi
s="hello123"
[[ $s =~ [0-9]+ ]] && echo "has number"
Step 7: Command Substitution and Subshells
echo "Today: $(date +%Y-%m-%d)"
(cd /tmp; ls)
Step 8: Redirection and File Descriptors
echo "Hello" > <<file>>
echo "Append" >> <<file>>
wc -l < <<file>>
ls /nope 2> err.log
echo "Error" >&2
exec 3> custom.log
echo "via fd3" >&3
exec 3>&-
File Descriptor Reference
| FD | Name | Description | Example |
|---|---|---|---|
0 |
stdin | Input | < file.txt |
1 |
stdout | Normal output | echo test > out.txt |
2 |
stderr | Error output | ls /nope 2> err.log |
3+ |
Custom | User-defined streams | exec 3> log.txt |
FD3 is a custom descriptor:
exec 3> process.log
echo "start" >&3
exec 3>&-
Step 9: Traps and Error Handling
set -e
set -u
set -x
set -o pipefail
trap 'echo done' EXIT
trap 'echo error' ERR
Step 10: Job Control
sleep 10 &
jobs
fg %1
bg %1
disown %1
kill %1
Job Reference (%1)
Example:
sleep 60 &
jobs
Output:
[1]+ Running sleep 60 &
| Symbol | Meaning |
|---|---|
%1 |
Job ID 1 |
%+ |
Current job |
%- |
Previous job |
Step 11: Reserved Commands
: # No-op
true
false
source ~/.bashrc
eval "echo executed"
{ echo A; echo B; }
Summary
This guide comprehensively covered Bash’s special syntax, expansions, variables, metacharacters, and control structures.
Understanding these concepts enables you to write safe, reusable, and automation-ready shell scripts.
