Page History

Shell Scripting

Mark George edited this page on 14 May

Clone this wiki locally

Conditional Statements

if test; then
elif test; then

test can be:

  • A bare command (no additional brackets) in which case the if will switch on the exit result of the command.
  • A simple expression in which case double square brackets are used [[ expression ]]. The expression can use standard comparison operators (==, !=, >, >=) etc.
  • Integer arithmetic in which case double round brackets are use (( expression )). This works on integers only.

Be careful with spaces. In general put spaces around everything since the double brackets are actually commands and need to be obviously separated from the expressions.

Process Substitution

Allows you to treat the stdout of a command as a file input to another command. In Z Shell there are two variants:

  • <() creates a FIFO to hold the sub-command's output (which is removed on completion). This also works in Bash.
  • =() creates a temporary file (in /tmp which is removed on completion) which is much more reliable — if a FIFO doesn't work, this might. This is Z Shell only.

The <() expression returns the path to the FIFO that holds the sub-command's output via command substitution. Likewise, =() returns the path to the temporary file. You can see this using:

echo <(echo foo)
echo =(echo foo)

Example — diff a local file against the output of another command:

diff -day --color localfile <(othercommand)

FYI — the parameters for the diff command here are:

  • -d — try harder to find minimal diff set
  • -a — treat files as text (not generally needed, but makes the parameter list an easy to remember mnemonic)
  • -y — side-by-side output
  • --color — colorize the diffs (red for deletions, green for additions)

Non-capturing groups with grep

Grep doesn't support capture groups, but you can fake it with a combination of Perl look-behind/ahead groups and --only-matching to exclude things. Basically we are using groups to exclude stuff we don't want rather than capture the stuff we do want:

grep --only-matching --perl-regexp "(?<=excluded start stuff)captured stuff(?=excluded end stuff)"

This works pretty well so long as the groups are fixed length — you can't use wild-cards in the look-behind/ahead groups, but you can in the non-group text.

Processing a chunk of text from stdin

Something I regularly need to do is format a chunk of unformatted JSON. This can be done using:

read json; echo ${json} | jq .

Run the command, then paste the JSON into the terminal.

The read var; echo ${var} | some_command technique is handy for processing chunks of text without creating temporary files.