CrackOps
Interview PrepTracksLinuxAWS LabSoonInterview RoomSoon
Sign inStart free
CrackOps

Interview prep for the people who keep production up.

[email protected]
ProductInterview PrepTracksDashboardInterview Room
RolesDevOpsSREPlatformCloud
CompanyAboutContactPrivacyTerms
© CrackOps
Linux / Shell Scripting / bash: if

bash: if

Conditions: if, elif, else, test brackets and case

Beginnerbashscriptingconditions

if runs a command and branches on its exit status: 0 means true. The command is usually a test: [[ ]] for files and strings, (( )) for numbers, or any real command like grep -q. case picks between many string patterns. Together they let a script check its environment before doing anything risky.

Syntaxif CMD; then ...; elif CMD; then ...; else ...; fi case WORD in PATTERN) ...;; esac

Watch it run

A monitoring check must print OK, WARNING or CRITICAL for a filesystem and exit 0, 1 or 2, like a Nagios plugin.

devops@devops-lab: ~/scripts — zsh — 96×28
➜ ~/scripts
Step 1 of 4
cat disk-check.sh

tr -dc '0-9' strips everything but digits, so ' 92%' becomes 92. (( )) compares integers with normal operators. Branches are checked top to bottom; the first true one runs.

Anatomy of a command

$
keywordif

Runs the command list that follows and checks its exit status. 0 is true, anything else false.

How it works

if is not a comparison operator: it executes the command after it and looks only at the exit status. [ is a real command (also /usr/bin/[) that evaluates its arguments and exits 0 or 1, which is why it needs spaces around it and a closing ] argument. Because [ is an ordinary command, the shell has already expanded and word-split its arguments, so an empty or multi-word variable changes the number of arguments and produces errors like 'unary operator expected'. [[ ]] is a bash keyword parsed before expansion: no word splitting or globbing happens inside, && || and ( ) work, == does glob matching and =~ regex matching. (( )) evaluates C-style integer arithmetic and returns 0 when the result is non-zero, so (( usage >= 90 )) reads naturally. Inside [[ ]], > and < compare strings alphabetically, not numbers. case compares one word against glob patterns top to bottom and runs the first branch that matches.

Options you'll actually use

[[ -f F ]] / -d / -eRegular file exists / directory exists / anything exists
-r -w -x FReadable / writable / executable by the current user
-s FExists and is not empty
-z S / -n SString is empty / not empty
S1 == S2, !=String equal / not equal; right side may be a glob (prod*)
S =~ REGEXRegex match; captures land in BASH_REMATCH
(( a >= b ))Integer comparison: == != < <= > >=
-eq -ne -lt -le -gt -geInteger comparison inside [ ] or [[ ]]
F1 -nt F2F1 is newer than F2 (modification time)
! CMDNegate the exit status of a command or test
case $x in a|b) ;; *) ;; esacMatch a value against several glob patterns

Common mistakes

if [ $status = "failed" ]

If $status is empty or contains spaces, [ gets the wrong number of arguments: 'unary operator expected' or 'too many arguments'.

if [[ $status == failed ]] # or: [ "$status" = failed ]
if [[ $count > 9 ]]

> inside [[ ]] compares strings alphabetically, so 10 > 9 is false.

if (( count > 9 )) # or: [[ $count -gt 9 ]]
if [$x -eq 1] or if [ $x -eq 1]

[ is a command and ] is its last argument; both need spaces around them.

if [ "$x" -eq 1 ]
if [ grep -q ERROR app.log ]

The brackets make it a test of the words 'grep', '-q'... instead of running grep.

if grep -q ERROR app.log; then
cmd && echo ok || echo failed used as if/else

If echo ok itself fails (e.g. stdout closed), the 'failed' branch also runs. It's not a true if/else.

if cmd; then echo ok; else echo failed; fi

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    Write a one-liner that prints 'exists' if /etc/hosts is a regular file and 'missing' otherwise.

  2. 2

    Print 'big log' if ~/logs/app.log has more than 1000 lines.

  3. 3

    Set env=prod and write a case statement that prints 'careful' for prod or production, 'fine' for anything else.

  4. 4

    Print 'FATAL found' only if ~/logs/app.log contains FATAL, using grep's exit status (no brackets).

Related commands

bash: exit codesExit codes, $?, set -euo pipefail and trapbash: variablesShell variables: assign, quote, default and exportbash: loopsLoops: for, while read, until and retrygrepSearch text for lines that match a pattern
Previousbash: variablesNextbash: loops
Linux / Shell Scripting / bash: if

bash: if

Conditions: if, elif, else, test brackets and case

Beginnerbashscriptingconditions

if runs a command and branches on its exit status: 0 means true. The command is usually a test: [[ ]] for files and strings, (( )) for numbers, or any real command like grep -q. case picks between many string patterns. Together they let a script check its environment before doing anything risky.

Syntaxif CMD; then ...; elif CMD; then ...; else ...; fi case WORD in PATTERN) ...;; esac

Watch it run

A monitoring check must print OK, WARNING or CRITICAL for a filesystem and exit 0, 1 or 2, like a Nagios plugin.

devops@devops-lab: ~/scripts — zsh — 96×28
➜ ~/scripts
Step 1 of 4
cat disk-check.sh

tr -dc '0-9' strips everything but digits, so ' 92%' becomes 92. (( )) compares integers with normal operators. Branches are checked top to bottom; the first true one runs.

Anatomy of a command

$
keywordif

Runs the command list that follows and checks its exit status. 0 is true, anything else false.

How it works

if is not a comparison operator: it executes the command after it and looks only at the exit status. [ is a real command (also /usr/bin/[) that evaluates its arguments and exits 0 or 1, which is why it needs spaces around it and a closing ] argument. Because [ is an ordinary command, the shell has already expanded and word-split its arguments, so an empty or multi-word variable changes the number of arguments and produces errors like 'unary operator expected'. [[ ]] is a bash keyword parsed before expansion: no word splitting or globbing happens inside, && || and ( ) work, == does glob matching and =~ regex matching. (( )) evaluates C-style integer arithmetic and returns 0 when the result is non-zero, so (( usage >= 90 )) reads naturally. Inside [[ ]], > and < compare strings alphabetically, not numbers. case compares one word against glob patterns top to bottom and runs the first branch that matches.

Options you'll actually use

[[ -f F ]] / -d / -eRegular file exists / directory exists / anything exists
-r -w -x FReadable / writable / executable by the current user
-s FExists and is not empty
-z S / -n SString is empty / not empty
S1 == S2, !=String equal / not equal; right side may be a glob (prod*)
S =~ REGEXRegex match; captures land in BASH_REMATCH
(( a >= b ))Integer comparison: == != < <= > >=
-eq -ne -lt -le -gt -geInteger comparison inside [ ] or [[ ]]
F1 -nt F2F1 is newer than F2 (modification time)
! CMDNegate the exit status of a command or test
case $x in a|b) ;; *) ;; esacMatch a value against several glob patterns

Common mistakes

if [ $status = "failed" ]

If $status is empty or contains spaces, [ gets the wrong number of arguments: 'unary operator expected' or 'too many arguments'.

if [[ $status == failed ]] # or: [ "$status" = failed ]
if [[ $count > 9 ]]

> inside [[ ]] compares strings alphabetically, so 10 > 9 is false.

if (( count > 9 )) # or: [[ $count -gt 9 ]]
if [$x -eq 1] or if [ $x -eq 1]

[ is a command and ] is its last argument; both need spaces around them.

if [ "$x" -eq 1 ]
if [ grep -q ERROR app.log ]

The brackets make it a test of the words 'grep', '-q'... instead of running grep.

if grep -q ERROR app.log; then
cmd && echo ok || echo failed used as if/else

If echo ok itself fails (e.g. stdout closed), the 'failed' branch also runs. It's not a true if/else.

if cmd; then echo ok; else echo failed; fi

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    Write a one-liner that prints 'exists' if /etc/hosts is a regular file and 'missing' otherwise.

  2. 2

    Print 'big log' if ~/logs/app.log has more than 1000 lines.

  3. 3

    Set env=prod and write a case statement that prints 'careful' for prod or production, 'fine' for anything else.

  4. 4

    Print 'FATAL found' only if ~/logs/app.log contains FATAL, using grep's exit status (no brackets).

Related commands

bash: exit codesExit codes, $?, set -euo pipefail and trapbash: variablesShell variables: assign, quote, default and exportbash: loopsLoops: for, while read, until and retrygrepSearch text for lines that match a pattern
Previousbash: variablesNextbash: loops