Read

Module 10 · Putting it all together

Chaining: ;, &&, ||, subshells and grouping

Join commands on one line so each step runs only when it should, isolate changes in a subshell with ( ), and redirect a whole group at once with { }.

What you will learn

  • Choose between `;`, `&&` and `||` based on exit status.
  • Avoid the `a && b || c` trap.
  • Use `( … )` to isolate `cd` and variables, and `{ …; }` to redirect several commands together.

Lesson 89 introduced && and || inside scripts. They are just as useful at the prompt, where a well-built one-liner can replace a small script. Every operator in this lesson relies on the exit status of the command on its left: 0 is success, anything else is failure.

FormRuns B whenTypical use
A ; BAlways, after A finishesIndependent steps
A && BA succeededSteps that depend on the previous one
A || BA failedFallbacks and error messages
! A(inverts A's status)"if it is NOT there"
~% mkdir lab/l96/build && cd lab/l96/build && echo "ready"
ready
build% cd /nope && rm -rf *
sh: cd: can't cd to /nope: No such file or directory
build% cp custom.conf app.conf 2>/dev/null || cp default.conf app.conf
build% grep -q root /etc/passwd && echo "root exists" || echo "no root"
root exists

Look at the second line: with &&, the dangerous rm -rf * never runs because the cd failed. Had it been written with ;, it would have deleted everything in the current directory. Whenever a command only makes sense if the previous one worked, join them with &&. Use || to provide a plan B: copy the custom file, or if that fails, the default one.

Subshells: ( … )

Commands inside parentheses run in a child shell. Whatever they change, the working directory, variables, umask, is thrown away when the parentheses close. That makes them perfect for "go there, do something, and come back" without having to remember where you were.

~% pwd
/root
~% (cd /etc && ls | wc -l)
24
~% pwd
/root
~% x=1; (x=2; echo "inside: $x"); echo "outside: $x"
inside: 2
outside: 1

Grouping: { …; }

Braces also group commands, but they run in the current shell, so a cd inside them sticks. Their main use is to treat several commands as one for a redirection or a pipe: one > captures the output of all of them. The syntax is picky: a space after { and a ; (or newline) before }, because { and } are reserved words, not symbols.

~% { hostname; uname -r; date +%Y; } > lab/l96/info.txt
~% cat lab/l96/info.txt
(none)
4.16.13
2026
~% { echo "== users"; cut -d: -f1 /etc/passwd; } | head -3
== users
root
daemon

Without the braces, hostname; uname -r; date > info.txt would redirect only date. Two more details round off the topic. The exit status of a pipeline is that of its last command, so grep x f | sort && echo ok tests sort, not grep. And $( … ), which you used for command substitution, is itself a subshell: a cd inside it never affects you.

Commands in this lesson

CommandWhat it does
a ; bRun a, then b, regardless.
a && bRun b only if a succeeded.
a || bRun b only if a failed.
! aInvert a's exit status.
( cd dir && cmd )Subshell: changes do not leak out.
{ a; b; } > fileGroup in the current shell; one redirection for all.

Quiz

  1. Which line removes files only if the `cd` worked?

    • `cd /tmp/work ; rm -f *.tmp`
    • `cd /tmp/work && rm -f *.tmp`
    • `cd /tmp/work || rm -f *.tmp`
  2. After `(cd /etc)`, where are you?

    • In /etc
    • Where you were before
    • In your home directory
  3. What is wrong with `{ date; uname -r }`?

    • Nothing.
    • It needs a `;` before the closing `}`.
    • Braces cannot contain two commands.
  4. In `A && B || C`, when does C run?

    • Only when A fails
    • When A fails or when B fails
    • Always
  5. Which captures the output of three commands in one file with a single redirection?

    • `a; b; c > out.txt`
    • `{ a; b; c; } > out.txt`
    • `a && b && c >> out.txt`

Practice

  1. In a single command line, create the directory `/root/lab/l96/build` and, only if that worked, write `1.0` into `/root/lab/l96/build/VERSION`.

  2. Write a one-liner that copies `/root/lab/l96/custom.conf` to `/root/lab/l96/app.conf`, and if that fails (it will: custom.conf is missing), copies `/root/lab/l96/default.conf` there instead.

  3. With a single redirection, save the output of `hostname`, `uname -r` and `date +%Y` (in that order, three lines) into `/root/lab/l96/info.txt`.

Open this lesson in the app to do the tasks in a real Linux machine and have them checked.