The shell environment

INPUT · Slides

How a command gets found (`PATH`)

01 / 06

Where is ls?

You have been typing ls all along, but where is ls?

~ $ which ls/bin/ls

An ordinary file called /bin/ls. The /bin you saw on the map in chapter 9.

Which means what you were typing was the short way of writing this.

~ $ /bin/ls        the same thing

So why is ls on its own enough? The answer is the variables of last lesson.

~ $ echo $PATH/bin:/sbin:/usr/bin:/usr/sbin

That is the list of places where commands are looked for, four of them, separated by :.

1. look in /bin2. look in /sbin3. look in /usr/bin4. look in /usr/sbin

Type ls and the shell goes to those four in order, and runs the first thing it finds.

Not magic, was it. It only searches the places written in a variable, from the top.

02 / 06

What command not found really means

Understand the mechanism and the commonest error makes sense too.

~ $ greet-sh: greet: not found

It does not mean "no such command exists". Properly, it means this.

> I looked in every place listed in PATH and there was no file called greet

So the cause narrows to two.

1. it really is not installed     ->  install it2. it is, but not on PATH         ->  add it to PATH, or type the full path

The second is commoner than you would think, especially with tools you made yourself, or software installed somewhere unusual like /opt.

The exit status is fixed too.

~ $ greet~ $ echo $?127

The 127 from last lesson. 127 is the number reserved for "command not found".

Knowing it lets you tell them apart inside a script.

1    the command ran and failed127  there was no command at all

The causes are entirely different, so it is a mercy they are kept apart.

03 / 06

Build a toolbox of your own

A script you wrote can be called by name too.

~ $ mkdir bin~ $ echo '#!/bin/sh' > bin/greet~ $ echo 'echo hello' >> bin/greet~ $ chmod +x bin/greet~ $ greet-sh: greet: not found     <- still not callable

You gave it the execute mark and still it is not found, because it is not on PATH.

Add it and this happens.

~ $ PATH=$PATH:$HOME/bin~ $ greethello

It runs. Look closely at how it is written.

PATH=$PATH:$HOME/bin     ^     ^  what is there now   the place added on

It adds to the end without destroying what is there. The "variable into a variable" shape from last lesson.

Forget it and things get nasty.

PATH=$HOME/bin      <- you threw away what was there!

Type that and ls and cat stop working. It comes back if you keep calm and type export PATH=/bin:/sbin:/usr/bin:/usr/sbin, but get into the habit of the $PATH: from the start.

04 / 06

The order decides who wins

What do you suppose happens with a tool of the same name in two places?

~ $ PATH=$HOME/bin2:$PATH     added at the front~ $ greetsecond box

Whichever is earlier in PATH wins, because the search goes in order and stops at the first thing found.

PATH=/home/learner/bin2:/bin:/sbin:...           ^ found here, and it looks no further

So where you add matters.

How you write itMeaning
PATH=$PATH:new placeadd at the end (what is there wins)
PATH=new place:$PATHadd at the front (the new one wins)

When you install a new version and the old one keeps running, this is why.

which that-command    ->  tells you which is running

which is precisely the command that searches PATH in order and answers with the first thing it finds. It only does by hand what you would do.

And a word on safety. Never put . (where you are) at the front of PATH. cd into somewhere with a malicious ls in it and that is what runs.

05 / 06

The ones built into the shell

Some commands do not search PATH.

~ $ type cdcd is a shell builtin~ $ type lsls is /bin/ls

cd is built into the shell itself. It does not exist as a file.

which cd    ->  nothing comes out (there is no file)type cd     ->  it tells you: builtin

Can you see why cd has to be built in?

if cd were a separate program  -> it starts as a child process  -> it moves about inside that child  -> the child finishes  -> the parent (your shell) has not moved!

The same story as "a variable made in a child is not left for the parent", from last lesson. To change where you are, you have to do it yourself.

Other built-in ones include these.

cd  export  unset  echo  read  set  exit  .  eval

echo is the odd one out, being both a builtin and present as /bin/echo.

Here are the three ways of finding out what a tool is.

What you typeWhat it tells you
which namewhere it lives within PATH
type namewhether it is a builtin or a file
command -v nameclose to type (suits scripts)

06 / 06

Now have a go

Here are the shapes for this lesson.

echo $PATH                     see the list of places searchedtr ':' '\n' < what-you-wrote     read it a line at a timewhich ls                       find where it livestype cd                        find whether it is a builtinPATH=$PATH:$HOME/bin           add at the endPATH=$HOME/bin:$PATH           add at the front (make it win)./tool.sh                      call it directly, without PATH$HOME/bin/tool.sh              call it by the full path

PATH separated by : is hard to read. The tr of chapter 5 breaks it into lines.

~ $ echo $PATH | tr ':' '\n'/bin/sbin/usr/bin/usr/sbin

Making something new readable with tools you know. A move you have used many times.

The tool you make here joins up with chapters 6 and 11.

ch 6    give it the execute mark with chmod +xch 10   put it on PATH and call it by namech 11   write the inside of it properly

Today, only "make it callable by name". One line of contents will do. Let us type.