Course outline · 0% complete

0/29 lessons0%

Course overview →

Your first script

lesson 8-1 · ~10 min · 21/29

Two earlier ideas meet here. A script of your own is run as ./deploy.sh rather than deploy.sh because the current directory is not on PATH (lesson 7-1), so an explicit path is required. And before it will run at all, the file needs execute permission, which means chmod +x deploy.sh (lesson 6-1).

This lesson puts both to work at once.

A script is just commands in a file

Scripts are the destination this whole course has been driving toward: every deploy pipeline, scheduled job, and "run this to set up the project" file you'll meet in industry is a shell script. The professional instinct: the second time you type the same five commands, put them in a file.

Everything you've typed so far, you can save and replay. A bash script is a plain text file of commands, run top to bottom. Three ingredients:

  1. The shebang. The first line #!/bin/bash tells the OS which program should interpret this file. (# starts a comment anywhere else, so use comments liberally.)
  2. Execute permission: chmod +x script.sh (lesson 6-1).
  3. Run it by path: ./script.sh (lesson 7-1 explained why the ./).

You can also skip steps 2-3 and run any script with bash script.sh. Both forms are everywhere in real projects.

Building and running hello.sh

This example builds hello.sh out of echo lines, which makes it a script that writes a script, then marks it executable and runs it by path.

echo '#!/bin/bash' > hello.sh
echo 'echo "Hello from my first script"' >> hello.sh
chmod +x hello.sh
./hello.sh

Output

Hello from my first script

The single quotes around each echo argument matter more than they look. They stop the outer shell from expanding anything while the file is being written, so hello.sh ends up containing exactly the two intended lines. Adding a cat hello.sh before the final line would print the file that was built.

A script with a variable at the top

Scripts get powerful the moment they combine with unit 7's variables: define a value once at the top, then use it everywhere below. In this script the project name appears in two messages but is written as data only once.

echo '#!/bin/bash' > stamp.sh
echo 'project="atlas"' >> stamp.sh
echo 'echo "deploying $project"' >> stamp.sh
echo 'echo "deploy of $project finished"' >> stamp.sh
chmod +x stamp.sh
./stamp.sh

Output

deploying atlas
deploy of atlas finished

There are two levels of quoting at play. The single quotes around each echo line keep $project literal while the script is being written, and the expansion happens later, when the script runs. Because of that, editing atlas to another name on its one line would change both output lines together.

The first line #!/bin/bash tells the OS which program should interpret the file. Those two opening characters, #!, are called the shebang, and what follows is the path to the interpreter.

With that line present, running ./script.sh really amounts to running /bin/bash script.sh. The mechanism is not specific to bash either: a Python file can begin with #!/usr/bin/env python3 and become directly runnable in exactly the same way.

The same three-step pattern builds any script: write the shebang with >, append the body with >>, then make it executable before running it.

echo '#!/bin/bash' > goodbye.sh
echo 'echo "So long"' >> goodbye.sh
echo 'echo "and thanks for all the fish"' >> goodbye.sh
chmod +x goodbye.sh
./goodbye.sh

Output

So long
and thanks for all the fish

What each part is doing

  • The first line uses > to create the file, and every line after it uses >> so nothing gets overwritten.
  • Each appended line is wrapped in single quotes, which lets the inner double quotes survive into the file intact.
  • chmod +x has to come before ./goodbye.sh, since without the execute bit the shell would refuse to run it.