Write a script

INPUT · Slides

`#!` and the execute mark

01 / 08

When typing three lines becomes a bother

Say you do this every day.

~ $ df -h > record.txt~ $ du -sk * >> record.txt~ $ date >> record.txt

Typing three lines is honestly a bother. And you get the order wrong, or forget a line.

At times like this you think of it this way.

> Write the steps in a file, and call it by name

That file is called a script. You have already seen one: you looked inside ~/bin/greet in chapter 10.

#!/bin/shecho hello

That is a script. Two lines.

What this chapter does is, in fact, half done already.

you can type commands        <- you canyou can write to a file      <- you can (echo and >>)you can put the execute mark <- you can (chmod +x)

It is a combination of chapters 6 and 10. All that is left is the #! on the first line.

02 / 08

Make it, mark it, call it

Three steps.

~ $ echo '#!/bin/sh' > check.sh~ $ echo 'pwd' >> check.sh~ $ chmod +x check.sh~ $ ./check.sh/home/learner

It ran! In order:

1. Write the contents

echo '#!/bin/sh' > check.sh    the first lineecho 'pwd' >> check.sh         add the second

Start with > and add with >>. The distinction from chapter 4, the same as .profile in chapter 10.

2. Put the execute mark on

chmod +x check.sh

The x mark from chapter 6. Without it, nothing runs.

3. Call it with ./ in front

./check.sh

./ meant "of the place I am in". In the second lesson of chapter 10 you saw that . is not on PATH, so without it nothing is found.

Write, mark, call. Remember those three and you can write a script.

03 / 08

#! names the tool to run it with

What is this first line?

#!/bin/sh

It names the tool that runs this file. It means "have /bin/sh read it".

It is called a shebang, a name made of # and ! together.

There is an entertaining experiment for seeing what it really is. Write cat instead of sh.

#!/bin/catthis comes out

Run it and you get this.

~ $ ./s.sh#!/bin/catthis comes out

The file itself came out. Which means it works like this.

./s.sh  | read the first line -> it says use /bin/cat/bin/cat s.sh

It hands the file to the tool named after #!, no more than that. Once you see the mechanism it is not frightening.

So other languages take the same shape.

#!/bin/sh          a shell script#!/usr/bin/python  Python#!/usr/bin/node    JavaScript

Change the first line and the language inside changes.

04 / 08

Why does a # line do anything?

You may have wondered. Everything after # is a comment and ignored, surely.

#!/bin/sh      <- starts with #

Quite so, and the shell does ignore this line. Somebody else reads it.

1. Linux (the kernel) looks at line 1  ->  a #!  Let us use /bin/sh2. /bin/sh reads the file              ->  line 1 starts with #, so ignore it

There are two readers. Which is why you get the curious shape of "a comment that does something". Neatly arranged, is it not.

Thanks to that arrangement it runs even without a #!.

echo pwd > s.shchmod +x s.sh./s.sh          -> it runs

The shell takes care of it, guessing "probably a shell script".

But do write it, for two reasons.

1. the reader can tell which language you wrote in2. it runs the same even for someone on a different shell

One line at the top heads off all the confusion that would follow.

05 / 08

Telling the two errors apart

Two kinds of error come out here. Look at both.

When you forget the mark

~ $ ./s.sh-sh: ./s.sh: Permission denied

You forgot chmod +x s.sh. It is saying "not allowed".

When you forget the ./

~ $ s.sh-sh: s.sh: not found

The file is right in front of you and it says "not there". This means it looked along PATH and did not find it. The second lesson of chapter 10.

Here is the table for telling them apart.

What came outWhat is missing
Permission deniedthe execute mark (chmod +x)
not foundthe ./ (or PATH)

There is one more, a nastier one.

~ $ ./s.sh-sh: ./s.sh: not found

not found even with the ./? That is when the tool named after #! cannot be found.

#!/bin/shh      <- misspelt

What it says is missing is not the script but the tool. When this happens, suspect the first line.

06 / 08

sh s.sh works too

There is a way to run it without the mark.

~ $ sh s.sh

You hand it to sh to read. In this shape you need neither chmod +x nor ./.

Set the two shapes side by side.

./s.sh      call it as a file that runs by itselfsh s.sh     have sh read it

The result is the same, but the meaning differs.

./s.sh    "this is a tool"sh s.sh   "this is text for sh to read"

How to choose.

handing it on, using it daily   ->  mark it and call with ./just trying something           ->  sh s.sh will do

And the distinction from chapter 10 comes round again.

./s.sh       runs in a child shell. ./s.sh     runs in this shell

With a single dot . it is read in the shell you are in. Only scripts that put settings in take that shape.

There are four ways of calling, but the one you use daily is ./s.sh.

07 / 08

Put it in ~/bin and call it by name alone

When the ./ starts to bother you, think back to the settings of chapter 10.

PATH="$PATH:$HOME/bin"

Write that in .profile and things inside ~/bin can be called by name alone.

~ $ mv check.sh ~/bin/check~ $ check/home/learner

No ./ and no .sh. A command of your very own.

A word about extensions.

check.sh    a .sh is finecheck       so is none

Linux does not decide behaviour by the extension. What decides is the #! and the execute mark. Look inside /bin and you will not find a name like ls.sh.

something you are trying out   a .sh like s.sh makes it clearsomething become a tool        no extension is easier to type

Either does, but dropping the extension once it is a tool is the tidy way. It takes the same shape as the ls and cat you type.

08 / 08

Now have a go

Here are the shapes for this lesson.

echo '#!/bin/sh' > s.sh     write the first lineecho 'pwd' >> s.sh          add what followschmod +x s.sh               the execute mark./s.sh                      call itsh s.sh                     try it without the markcat s.sh                    check the contents

echo and >> are enough for writing. vi comes in chapter 13, so add lines this way until then.

And here is the most important thing in this lesson.

> A script is the commands you typed, lined up as they were

There is no new way of writing to learn. You just write down, from the top, what you have been typing all along.

you can type  ->  you can write  ->  you can call

The rest of this chapter is about making them cleverer.

next        hand in values from outside ($1)after that  branch on a condition (if)after that  repeat (for / while)

But the foundation is today's three steps. Let us make one.