Skip to content

Complete Guide to Bash Special Syntax, Variables, and Expansions

This article provides a comprehensive summary of all special syntax, variables, expansion rules, and control structures used in Bash shell scripting.


Dynamic or environment-dependent values are denoted as <<variable>>.
All examples below explicitly show their usage.

VariableExampleDescription
<<var>>name, path, userArbitrary variable name
<<default>>guest, 8080Default or fallback value
<<pattern>>*.txt, */File or string pattern
<<offset>>0, 3Starting index of substring (0-based)
<<length>>4, 10Length of substring
<<prefix>>ENV_, HOSTPrefix pattern for variable names
<<index>>0, 1, 2Array or associative key index
<<file>>/tmp/test.txtFile path

SymbolMeaningExample
*Matches any stringls *.txt → lists all .txt files
?Matches any single characterls ?.sh → matches a.sh, b.sh
[a-z]Range matchls [A-Z]* → files starting with uppercase
{a,b}Brace expansionmv {hoge,huga}
{1..3}Sequence expansiontouch file{1..3}.txt
$Variable expansionecho $HOME
! (negation)Logical NOT[[ ! -f test.txt ]]
! (history)History expansion!10 → reruns command #10
~Home directorycd ~
;Command separatorpwd; ls
&&Execute if previous succeededmake && echo OK
``
&Run in backgroundsleep 5 &
``Pipe output
>Redirect stdoutecho hi > out.txt
>>Append outputecho hi >> out.txt
<Redirect stdinwc -l < file.txt
()Subshell(cd /tmp; ls)
{}Same shell block{ echo A; echo B; }
\Escape characterecho \$HOME
' 'Literal (no expansion)echo '$USER'
" "Expand variablesecho "$USER"

VariableDescriptionExample
$0Script nameecho $0script.sh
$1–$9Positional argsecho $1
$@All args as arrayfor a in "$@"; do echo $a; done
$#Arg countecho $#
$?Last exit statusls /nope; echo $?
$$Current PIDecho $$
$!Last BG job PIDsleep 10 & echo $!
$-Current shell optionsecho $-
$_Last arg of previous cmdecho $_
$PPIDParent PIDecho $PPID
$RANDOMRandom numberecho $RANDOM
$SECONDSSeconds since shell startecho $SECONDS
$FUNCNAMEFunction namef(){ echo $FUNCNAME; }; f
$PIPESTATUS[@]Exit status of pipe cmds`ls

SyntaxDescriptionExample
${<<var>>}Variable expansionname=user; echo ${name}
${<<var>>:-<<default>>}Use default if unsetecho ${user:-guest}
${<<var>>:=<<default>>}Assign default if unsetecho ${port:=8080}
${<<var>>:+alt}Use alt if setx=1; echo ${x:+OK}
${<<var>>:?msg}Error if unsetecho ${config:?missing}
${#<<var>>}String lengthname=user; echo ${#name}
${<<var>>%<<pattern>>}Remove shortest suffixpath=/a/b/c; echo ${path%/*}
${<<var>>%%<<pattern>>}Remove longest suffixecho ${path%%/*}
${<<var>>#<<pattern>>}Remove shortest prefixecho ${path#*/}
${<<var>>##<<pattern>>}Remove longest prefixecho ${path##*/}
${<<var>>/<<pattern>>/<<repl>>}Replace first matchecho ${msg/foo/bar}
${<<var>>//<<pattern>>/<<repl>>}Replace allecho ${msg// /_}
${<<var>>:<<offset>>}Substring from offsets=abcdef; echo ${s:2}
${<<var>>:<<offset>>:<<length>>}Substring with lengthecho ${s:1:3}
${!<<prefix>>*}Vars with prefixHOST1=x; HOST2=y; echo ${!HOST*}
${!<<var>>}Indirect referenceref=NAME; NAME=user; echo ${!ref}
${<<var>>,} / ${<<var>>^^}Case conversionn=abc; echo ${n^^}
${<<var>>@Q}Quoted formx='abc'; echo ${x@Q}

Terminal window
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

Terminal window
x=5; y=3
echo $((x + y)) # 8
((x *= 2))
echo $x # 10

Terminal window
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

Section titled “Step 7: Command Substitution and Subshells”
Terminal window
echo "Today: $(date +%Y-%m-%d)"
(cd /tmp; ls)

Terminal window
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>&-
FDNameDescriptionExample
0stdinInput< file.txt
1stdoutNormal outputecho test > out.txt
2stderrError outputls /nope 2> err.log
3+CustomUser-defined streamsexec 3> log.txt

FD3 is a custom descriptor:

Terminal window
exec 3> process.log
echo "start" >&3
exec 3>&-

Terminal window
set -e
set -u
set -x
set -o pipefail
trap 'echo done' EXIT
trap 'echo error' ERR

Terminal window
sleep 10 &
jobs
fg %1
bg %1
disown %1
kill %1

Example:

Terminal window
sleep 60 &
jobs

Output:

[1]+ Running sleep 60 &
SymbolMeaning
%1Job ID 1
%+Current job
%-Previous job

Terminal window
: # No-op
true
false
source ~/.bashrc
eval "echo executed"
{ echo A; echo B; }

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.