Bash Cheatsheet - Shell Scripting Command Reference

A script that runs is not the same as a script that is correct. Most bash failures in production come from three details: unquoted values that get word-split, an empty variable expanding into a malformed command, and a failing pipeline stage silently ignored because pipefail is off. The sheet covers six baseline groups — variables, conditionals, loops, functions, string operations and file tests — and closes with parameter expansion and debugging, the latter being what actually moves a script from running to correct. The variables group earns its place: ${var:-default} for a fallback, ${#var} for length and ${var//a/b} for global replacement handle cases that otherwise become chains of if statements. Within conditionals, [[ ]] beats [ ] because it skips word splitting and adds =~ matching plus && and || chaining. The functions group covers return conventions, the local keyword, and losing the quotes around "$@" — a common genuine bug. The debugging group covers set -x, set -u, set -euo pipefail and bash -n, and that last combo is worth making the first line of any script that is not throwaway.

SysOps·55 commands·Last updated 2026-09-10
bashshellScriptinglinux

Typical Use Case

Write scripts, process text and logs, batch rename and find files, compose pipelines on servers, and troubleshoot script permission, unexported variables, and unexpanded globs.

Variables 8

NAME="value"
Define variable (no spaces around =)
echo $NAME
Read variable
echo ${NAME}
Read variable (recommended, avoids ambiguity)
readonly NAME="value"
Define readonly variable
unset NAME
Delete variable
${VAR:-default}
Use default value if variable is empty
${VAR:=default}
Assign and use default if variable is empty
${#VAR}
Get string length

Conditionals 7

if [ condition ]; then ... fi
if statement
if [ -f file ]; then ... fi
Check if file exists
if [ $a -eq $b ]; then ... fi
Numeric comparison (-eq -ne -gt -lt)
if [ "$str" = "value" ]; then ... fi
String comparison (= !=)
if [[ $str =~ regex ]]; then ... fi
Regex match (double brackets)
[ -d dir ] && echo "exists"
Short-circuit evaluation
case $var in pattern1) ... ;; pattern2) ... ;; esac
case statement

Loops 6

for i in 1 2 3; do echo $i; done
for loop over a list
for ((i=0; i<10; i++)); do ... done
C-style for loop
while [ condition ]; do ... done
while loop
until [ condition ]; do ... done
until loop (executes while condition is false)
break / continue
Break out of loop / skip iteration
select var in list; do ... done
Interactive selection menu

Functions 7

function name() { ... }
Define a function
name() { ... }
Define function (shorthand)
name arg1 arg2
Call a function
$1 $2 $@
Positional parameters / all parameters
$#
Number of parameters
return 0
Return value (0 means success)
local var="value"
Local variable

String Operations 7

${VAR:offset:length}
Substring extraction
${VAR#pattern}
Remove shortest matching prefix
${VAR##pattern}
Remove longest matching prefix
${VAR%pattern}
Remove shortest matching suffix
${VAR%%pattern}
Remove longest matching suffix
${VAR/pattern/replacement}
Replace first match
${VAR//pattern/replacement}
Replace all matches

File Tests 8

[ -f file ]
File exists and is a regular file
[ -d dir ]
Directory exists
[ -e path ]
Path exists
[ -r file ]
File is readable
[ -w file ]
File is writable
[ -x file ]
File is executable
[ -s file ]
File size is greater than 0
[ file1 -nt file2 ]
file1 is newer than file2

Parameter Expansion & Debugging (REQ-02 add-on) 12

${var:-default}
Use default when var is unset or empty
${var:=default}
Assign default and write back when empty
${var:?message}
Exit with an error message when empty
${var#pattern}
Remove shortest match from the beginning
${var%pattern}
Remove shortest match from the end
${var/pattern/replace}
Replace the first match
${var^^}
Convert variable content to uppercase
${#var}
Get the character length of a variable
set -x
Enable execution trace of expanded commands
bash -n script.sh
Syntax-check a script without running it
shopt -s nullglob
Expand unmatched globs to empty instead of literal
getopts "a:b" opt
Parse short options in a script

Parameter matrix

ParameterEffectExample
-xPrint each command as it runs, handy for debugging scriptsbash -x script.sh
-eExit the script immediately when a command failsset -e
-uError out when an undefined variable is usedset -u
-o pipefailTreat the pipeline as failed if any stage failsset -eo pipefail
2>Redirect standard errorcmd 2>/dev/null
|Pipe: the output of the previous command becomes the input of the nextcat log | grep error | wc -l
$()Command substitution: capture the outputnow=$(date +%F)
&& / ||Run the second command only if the first succeeds / failsmake && make install
-name / -typefind by name / by typefind . -name "*.log" -mtime +7
-iIgnore case (in grep and the like)grep -ri error log/

Common pitfalls

SymptomThe script reports Permission denied and cannot run.

CauseThe file lacks the executable bit, or the shebang on the first line points to a nonexistent interpreter.

Fixchmod +x script.sh; make sure the first line is #!/usr/bin/env bash and the bash path exists.

SymptomThe variable is empty in a subshell or script.

CauseIt was not exported, or its scope is limited to the current shell.

FixUse export VAR=val to make it visible to child processes; declare variables consistently as local or global inside scripts.

SymptomThe for f in * glob does not expand and is treated as a literal.

CauseWhen the directory is empty and nullglob is off, * is passed to the command as-is.

FixEnable shopt -s nullglob; or handle the empty-directory case with find ... -print0 | xargs -0.

SymptomA redirection or pipe emptied the file.

CauseA command like cat file > file truncates the target before reading it.

FixRedirect to a different or temporary file and then overwrite; be careful about the direction of > and >>.

SymptomSpaces or special characters split a filename into multiple arguments.

CauseThe variable was not quoted, so IFS splits on spaces and tabs.

FixAlways wrap variables in "$var"; process filenames with while IFS= read -r line and find -print0.

Symptomrm deleted files it should not have.

CauseThe glob matched too broadly, or the path variable was empty.

Fixecho the matches before rm; add -i for confirmation on dangerous operations; avoid rm -rf "$dir"/* when the variable is empty.

Troubleshooting

  1. 1Debug each step of the script

    bash -x script.sh

    Print the commands actually executed and the variable expansions to locate logic errors.

  2. 2Confirm the script has no syntax errors

    bash -n script.sh

    Checks syntax only without executing; good for validation before release.

  3. 3Locate large files modified recently

    find /var -type f -size +100M -mtime -1

    Quickly surface suspicious files when investigating a disk spike.

  4. 4Count occurrences of errors in a log

    grep -ci error /var/log/app.log

    Quickly gauge the scale of errors, and use tail to see the latest samples.

Command Examples

Default a possibly-unset variable

NAME=${NAME:-lzh} echo "$NAME"

${var:-default} takes default when the variable is unset or empty; ${var-default} takes it only when completely unset.

Output

lzh   # outputs the default when NAME is unset; outputs the original value when set

Test whether a file exists

if [[ -f /etc/nginx.conf ]]; then echo exists else echo missing fi

Use [[ ]] instead of [ ]; it supports && and || and does not split words incorrectly; always quote variables to avoid syntax errors on empty values.

Output

exists

Resolve the directory of the running script

DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" echo "$DIR"

Use BASH_SOURCE[0] rather than $0, so that even when the script is sourced you get its real directory.

Output

/home/deploy/scripts

Common Pitfalls

  • Prefer [[ ]] and (( )) for tests and arithmetic; [ ] trips on empty variables or strings containing wildcards.
  • Quoting variables is a hard rule: for i in $LIST or rm $f without quotes split words or delete the wrong files when spaces or globs are involved.
  • set -e means fail fast: a failing line exits instead of continuing. Enable it in important scripts to avoid cascading failures.
  • Variables in functions are global by default; forgetting local pollutes globals and setups with the same name are easy to hit.
  • Both rm -rf and > redirection really delete or overwrite; echo the command as a preview or guard before running against production data.

Tips

  • No spaces around = in variable assignment, or it will be interpreted as a command.
  • Always quote variables ("$VAR") to avoid word splitting and special character issues.
  • [ ] is syntactic sugar for the test command; [[ ]] is a Bash extension with more features like regex matching.

FAQ

What do set -euo pipefail do respectively at the top of a Bash script?

set -e exits on an error, but a failing command does not trigger the exit when it appears in a condition such as if/while/&&/|| or in the middle of a pipeline; -u makes referencing an undefined variable an error; -o pipefail makes a pipeline return the rightmost non-zero exit code among its commands rather than only the last one. Combined they surface errors early and are the standard for robust scripts.

Why does a variable expand inside double quotes but not single quotes in Bash?

Inside double quotes, $variables, $(commands), and backticks are expanded normally, whereas single quotes treat everything literally with no expansion, which suits paths, regexes, or text that must stay untouched. Always wrap a variable holding a path you want to keep intact in double quotes, or word splitting will break it apart.

What is the difference between $@ and $* in Bash?

Without quoting both are equivalent and split the arguments on whitespace. The decisive difference appears when quoted: the @ form preserves each argument as a separate word, whereas the * form joins all arguments into one string. Prefer the quoted at-sign form when iterating over positional parameters.

How do I read a file line by line in Bash robustly?

Use while IFS= read -r line; do ...; done < file. IFS= prevents stripping leading and trailing whitespace, and -r keeps backslashes literal. Do not use for line in $(cat file), which splits the file into words on whitespace and loses line structure.

How do I check whether the previous command succeeded, and how do I make my script fail on purpose in Bash?

$? holds the exit status of the immediately preceding command, where 0 means success and non-zero means failure, so copy it into a variable before checking. Use exit 1 to exit with a non-zero status deliberately, while exit 0 signals success. Combined with set -e, the script automatically aborts on any uncaught failure.

Official References

Each command links to its official documentation below, so you can verify the latest usage and read deeper.

Maintained by LaoHand

Publicly updated on Sep 10, 2026, continuously proofread against official docs.

Contact Us

Wrong command or description? Send us corrections, business inquiries or product feedback by email.

Contact Us