Note that there must not be any space between #! and the path of the
interpreter /bin/bash.
Shell Scripting
Learn the basics of shell scripting with Bash.
You will need
- A Unix CLI
Recommended reading
What is a script?
In a Unix-like operating system, a file that can be executed should be one of the following:
- A binary file, which contains machine-readable binary code that has been compiled from source code.
- A script, which is a file containing code that is dynamically interpreted.
How is a script executed?
When an executable text file is run, a Unix-like operating system looks for a shebang on the first line. A shebang is a line with the following format:
#!interpreter optional-args
For example, the following is a valid shebang:
#!/bin/bash
In this example, it tells the operating system that the interpreter which
should run this file is /bin/bash, meaning that this is a Bash script.
What can I put in a script?
In a bash script, you can put anything you could type in a Bash shell:
#!/bin/bash
echo Hello World
In a PHP script, you can put any PHP code you want:
#!/usr/bin/php
<?php
echo 'Hello World';
?>
Basically, what you can put in a script depends on the interpreter you’re using.
How do I create a script?
Simply create your script:
$> printf '#!/bin/bash\necho Hello World' > test.sh
The printf (print format) command is similar to the echo command
but it has better support for special characters like new lines (\n).
Make it executable:
$> chmod +x test.sh
And run it:
$> ./test.sh
Hello World
All kinds of scripts
The following are a few examples of shebangs, but it is nowhere near exhaustive:
| Shebang | Script contents |
|---|---|
#!/bin/sh |
Bourne shell commands |
#!/bin/bash |
Bash shell commands |
#!/bin/zsh |
Z shell commands |
#!/usr/bin/node |
Node.js code |
#!/usr/bin/php |
PHP code |
#!/usr/bin/python |
Python code |
#!/usr/bin/ruby |
Ruby code |
Of course, the path to the interpreter must correspond to the actual path of the
command used (sh, bash, php, etc). It might differ on your machine. Use
which bash to find the location of the Bash executable, for example.
What is shell scripting?
Shell scripting is the practice of writing scripts that contain series of shell commands that you want to be able to reuse.
Any script with a shell as the interpreter is a “shell script”.
A script using PHP as the interpreter is still a script, but it’s not a “shell script”. It’s a PHP script.
Shell script basics
A few pointers on writing Bash scripts (compatible with most POSIX shells).
Commands
You can use any shell command in a shell script:
#!/bin/bash
echo Hello World
date
ls
This script could print:
Hello World
Thu Jan 10 23:46:52 CET 2019
file.txt directory ...
Working directory
By default, a script executes in the current shell directory.
You can use cd to move around to other directories:
#!/bin/bash
pwd
cd /home
pwd
This script could print:
/some/where/over/the/rainbow
/home
Assuming it was executed from the /some/where/over/the/rainbow directory.
Variables
You can declare and reuse variables in scripts:
#!/bin/bash
FOO=bar
echo $FOO
If your variable contains whitespace (spaces, new lines, etc), be sure to quote it when declaring and using it to avoid issues:
#!/bin/bash
FOO="bar baz"
echo "$FOO"
Store the output of commands
You can store the result of a command in a variable by wrapping it with backticks:
#!/bin/bash
FILES=`ls -1`
NUMBER_OF_FILES=`echo "$FILES" | wc -l`
echo There are $NUMBER_OF_FILES files
This script would output 10 if there are 10 files in the current directory.
Environment variables
Environment variables are also available as variables in shell scripts:
#!/bin/bash
echo $PATH
To set an environment variable, do it like you would in any Bash shell:
#!/bin/bash
export FOO=bar
The $FOO environment variable in this example will only be set in the context
of this script and its child processes.
Conditionals
Bash has a classic if/then/else construct:
#!/bin/bash
FOO="bar"
if [[ "$FOO" -eq "foo" ]]; then
echo FOO is foo
elif [[ "$FOO" -eq "bar" ]]; then
echo FOO is bar
else
echo foo is something else
fi
The [[ ]] syntax is a Bash test construct. Also see
Bash other comparison operators.
The test built-in command
The test command which comes with Bash is another way to write some conditions:
#!/bin/bash
EMPTY_VAR=
FULL_VAR="full"
FILE="/path/to/some/file"
if test -z "$EMPTY_VAR"; then
echo variable is empty
fi
if test -n "$FULL_VAR"; then
echo variable is not empty
fi
if test -f "$FILE"; then
echo file exists
else
echo file does not exist
fi
See Bash file test operators and other comparison operators.
Loops
Bash has a for loop:
for item in one two three; do
echo $item
done
The above code would print:
one
two
three
Bash also has while and until. See loops & branches.
Special variables
Bash has a number of special variables which are always available:
| Variable | Description |
|---|---|
$0 |
Name of the command being executed. |
$1 |
First argument passed to the script on the command line (and so on with $2, $3, etc). |
$@ |
All arguments passed to the script. |
$? |
Exit value of the last executed command. |
For example, this script says hello to the name passed as the first argument:
#!/bin/bash
echo Hello $1
The set built-in command
The set command is specific to Bash and can be used to toggle its option
flags.
For example, the -e option aborts the script if an error occurs, while the
-x option prints commands before executing them:
#!/bin/bash
set -ex
echo Hello World
cat file-that-does-not-exist
echo Done
This script could print:
+ echo Hello World
Hello World
+ cat file-that-does-not-exist
cat: file-that-does-not-exist: No such file or directory
Note that each command is printed with a leading + before being executed, and
that the script stops as soon as an error occurs (which is not the case by
default).
Functions
You can isolate pieces of code in a function. The special argument variables
$1, $2, etc represent the arguments to the function:
#!/bin/bash
print_hello() {
echo Hello $1
}
print_hello World
This script would print Hello World.
Variable scope
Note that normal Bash variables have no scope, i.e. they are available in the whole file and every function.
To declare a variable that is local to a function, use the local keyword:
#!/bin/bash
print_hello() {
local name=$1
echo Hello $name
}
print_hello World
echo $name
This script would print Hello World and an empty line,
since $name is only defined within the print_hello function.