Learn by reading through in order

Shell Script - Conditionals

Test files, strings and numbers with [ -f config.txt ], [ -z "$name" ] and [ "$count" -lt 5 ], branch with if / elif / else, and route multiple patterns with case — write and run each script, illustrated in a browser terminal.

Branch by comparing values — string and number comparisons

In a shell script you change what runs by checking whether strings match or numbers are larger.

For the check you use the test command, or [ ... ], which does the same thing.

The [ and ] need spaces just inside them, so you write [ "$count" -lt 5 ].

A true check returns exit code 0, and a false one returns 1.

Compare strings with = (equal) and != (not equal), and check for empty with -z (empty) or -n (non-empty).

Compare numbers with -eq (equal), -ne (not equal), -lt (less than) and -gt (greater than), and note that strings and numbers use different operators.

Wrap variables in double quotes like [ -z "$name" ] — that way the syntax stays valid even when the value is empty.

count=3
mode="dev"
[ "$count" -lt 5 ] && echo small    # 3 is less than 5, so small
[ "$count" -gt 0 ] && echo positive # greater than 0, so positive
[ "$mode" = "prod" ] || echo other  # not prod, so other
[ -z "$mode" ] || echo has-mode     # not empty, so has-mode
From comparison to branch
[ "$count" -lt 5 ]exit code 0exit code 1then blockelse blockif trueif falsetrue (0)false (1)
[ ... ] returns exit code 0 when true and 1 when false; if runs then on true and else on false.
SyntaxMeaningExample
[ "$a" = "$b" ]true if strings a and b are equal[ "$mode" = "prod" ]
[ "$a" != "$b" ]true if strings a and b differ[ "$mode" != "dev" ]
[ -z "$v" ]true if variable v is empty[ -z "$name" ] && echo empty
[ -n "$v" ]true if variable v is not empty[ -n "$name" ] && echo set
[ "$a" -eq N ]true if number a equals N[ "$count" -eq 0 ]
[ "$a" -ne N ]true if number a is not N[ "$count" -ne 0 ]
[ "$a" -lt N ]true if number a is less than N[ "$count" -lt 10 ]
[ "$a" -gt N ]true if number a is greater than N[ "$count" -gt 0 ]

Write a script that takes a number and a string as arguments and branches on their values.

① Open compare.sh with vi compare.sh, press i to enter insert mode, and write #!/bin/sh on the first line.

② Take the first argument $1 as a number, test it with -lt against some value, and print a different message when it is smaller and when it is not.

③ Then take the second argument $2 as a string, test it with = against some word, and print a different message when it matches and when it does not.

④ Press Esc, save with :wq, add execute permission, then run it with arguments like ./compare.sh 3 dev.

⑤ Change the arguments to ./compare.sh 8 prod and confirm that the branch taken changes.

⑥ If you are unsure what to write, copy the text in the answer panel and paste it into vi insert mode. (Run it correctly to reveal the explanation.)

Linux console
0 / 3 completed
Loading Linux Terminal...

Check files and folders — -f / -d

In a script you often check whether a config file exists or an output folder is ready before going further.

Test for a file with -f (a regular file exists) and for a folder with -d (a directory exists).

When you only care that something exists regardless of its kind, use -e, and to check that it is not empty, use -s.

You write these checks with the same [ ... ] as for strings and numbers, passing a path like [ -f config.txt ].

They return exit code 0 when true and 1 when false, so combined with if or && / || you can write use it if it exists, create it if it does not initialization.

touch report.txt                  # create the material
[ -f report.txt ] && echo exists  # the file exists, so exists
[ -d report.txt ] || echo notdir  # not a directory, so notdir
mkdir logs                        # create the folder
[ -d logs ] && echo hasdir        # the directory exists, so hasdir
Kinds of file tests
the path to test[ -f path ][ -d path ][ -e path ]true if aregular filetrue if adirectorytrue if itexists at allkind of testwhat makes it true
-f tests for a regular file, -d for a directory, and -e for existence of any kind. The same path can give different results depending on what you ask.
SyntaxMeaningExample
[ -f f ]true if f exists as a regular file[ -f config.txt ] && echo found
[ -d d ]true if d exists as a directory[ -d logs ] && echo dir
[ -e p ]true if p exists, any kind[ -e data ] && echo there
[ -s f ]true if f exists and is not empty[ -s log.txt ] && echo nonempty

Write a check script that branches on whether a file and a folder exist.

① Open setup.sh with vi setup.sh, press i to enter insert mode, and write #!/bin/sh on the first line.

② Test the target file with [ -f ... ] and print that you use it when it exists, or that you create a default when it does not.

③ Then test a log folder with [ -d ... ] and print a message for each case.

④ Press Esc, save with :wq, then add execute permission.

⑤ Run the script and confirm the check results are printed.

⑥ If you are unsure what to write, copy the text in the answer panel and paste it into vi insert mode.

Linux console
0 / 3 completed
Loading Linux Terminal...

Split the flow — if / elif / else

if runs the then block only when the condition is true.

To try several conditions in turn use elif, for the case where none match add else, and close with fi.

Separate the parts with semicolons as in if condition; then action; fi, or split them across lines.

count=3
if [ "$count" -eq 0 ]; then
  echo "none"
elif [ "$count" -lt 5 ]; then
  echo "few ($count)"
else
  echo "many ($count)"
fi                              # prints few (3)
if / elif / else flow
if [ A ]A blockelif [ B ]B blockelsefallback blocktruefalsetruefalsechecked top to bottomonly the first true branch runs
Starting at if, it tries each condition and runs only the first branch that becomes true. If none are true, it goes to else.
SyntaxMeaningExample
if cond; then … firun when the condition is trueif [ -f f ]; then echo ok; fi
thenstart the body when trueif [ -f f ]; then echo ok; fi
elif cond; then …try the next when the previous is falseelif [ "$n" -lt 5 ]; then …
else …run when none are trueelse echo other; fi
ficlose the ifif …; then …; fi

Write a check script that changes its message based on a count.

① Open check.sh with vi check.sh, press i to enter insert mode, and write #!/bin/sh on the first line.

② Set up a variable holding a number, then use if / elif / else to print different messages for -eq 0, for -lt a small value, and for everything else.

③ Press Esc, save with :wq, then add execute permission.

④ Run the script and confirm which branch it takes.

⑤ If you are unsure what to write, copy the text in the answer panel and paste it into vi insert mode.

Linux console
0 / 3 completed
Loading Linux Terminal...

Route multiple patterns — case

When you match one value against many candidates, case reads more clearly.

It has the form case value in pattern) action ;; esac, where you end each pattern with ;; and catch the no-match case with *).

It makes the intent of the branching clearer than stacking many if levels.

action="start"
case "$action" in
  start) echo "starting service" ;;
  stop)  echo "stopping service" ;;
  *)     echo "unknown action: $action" ;;
esac                            # prints starting service
case routing
case "$action" instart)stop)*)start action ;;stop action ;;fallback ;;pattern matchmatched action (;;)
case matches the value against patterns from the top, runs only the first matching branch, and closes with esac. *) is the no-match case.
SyntaxMeaningExample
case x in pat) … ;; esacroute a value to several patternscase "$1" in start) … ;; esac
pat)a pattern matched against the valuestart) echo go ;;
;;end of each case actionstart) echo go ;;
*)the no-match case*) echo other ;;
esacclose the casecase x in …; esac

Write a control script that takes an action name as an argument and routes on its value.

① Open service.sh with vi service.sh, press i to enter insert mode, and write #!/bin/sh on the first line.

② Take the first argument $1 as the action name, and with case route it into three patterns — start, stop, and everything else (*) — printing a different message for each. End each branch with ;; and close with esac.

③ Press Esc, save with :wq, add execute permission, then run it with an argument like ./service.sh start.

④ Change the argument to ./service.sh stop or ./service.sh restart and confirm the matching pattern changes.

⑤ If you are unsure what to write, copy the text in the answer panel and paste it into vi insert mode.

Linux console
0 / 3 completed
Loading Linux Terminal...
QUIZ

Knowledge Check

Answer each question one by one.

Q1What does [ -f config.txt ] test?

Q2Which keyword tries another condition when the previous one was false?

Q3Which symbol marks the end of each pattern's action in case?