Read

Module 10 · Putting it all together

PATH and installing your own commands

Turn a script into a real command: put it in ~/bin, add that directory to PATH for good, and check what the shell will run with which and type.

What you will learn

  • Explain how the shell searches `PATH` and why order matters.
  • Install a script as a command in `/root/bin`.
  • Extend `PATH` permanently in `/root/.profile` without breaking it.

When you type a word that is not an alias, a function or a builtin, the shell has to find a file to run. If the word contains a slash (./hello.sh, /bin/ls) it uses that path directly. Otherwise it walks through the directories listed in the variable PATH, separated by colons, from left to right, and runs the first executable file with that name. If none matches you get not found and exit status 127.

~% echo $PATH
/bin:/sbin:/usr/bin:/usr/sbin
~% which awk
/usr/bin/awk
~% command -v ls
/bin/ls
~% type cd
cd is a shell builtin
~% which nosuchtool; echo $?
1

which NAME prints the file the PATH search would pick (lesson 38). command -v NAME does the same and is built into the shell, so it also reports aliases and functions and is the portable choice in scripts: if command -v wget >/dev/null; then …. type NAME explains in words what the word is.

Your own bin directory

The convention for personal commands is a bin directory in your home: /root/bin for root. Put an executable script there, without the .sh suffix if you like (the shebang decides, not the name), and add the directory to PATH. From then on the script is a command like any other, usable from any directory and from other scripts.

~% mkdir -p /root/bin
~% printf '#!/bin/sh\necho "Hello from /root/bin"\n' > /root/bin/hello
~% chmod +x /root/bin/hello
~% hello
sh: hello: not found
~% PATH="$PATH:/root/bin"
~% hello
Hello from /root/bin
~% which hello
/root/bin/hello

Note how PATH is extended: PATH="$PATH:/root/bin" keeps the old value and appends one directory. Writing PATH=/root/bin would throw away /bin and /usr/bin, and suddenly ls, cat and almost everything else would be not found. If that happens, do not panic: builtins still work, so type PATH=/bin:/sbin:/usr/bin:/usr/sbin to repair it, or log in again.

Append or prepend?

Order decides who wins when two directories contain the same name. Appending ($PATH:/root/bin) means system commands win, which is the safe default. Prepending (/root/bin:$PATH) lets your ls replace the system one, useful for wrappers but easy to get wrong. Never put . (the current directory) in PATH: anyone who leaves a file called ls in a directory you visit could make you run it.

Making it permanent

A change to PATH typed at the prompt dies with the shell. Like aliases in the previous lesson, the permanent version goes in /root/.profile, read by every login shell. Use export so that scripts and other programs started from your shell inherit it too.

~% echo 'export PATH="$PATH:/root/bin"' >> /root/.profile
~% . /root/.profile
~% echo $PATH
/bin:/sbin:/usr/bin:/usr/sbin:/root/bin

Commands in this lesson

CommandWhat it does
echo $PATHShow the command search path.
which nameWhich file the PATH search finds.
command -v nameSame, builtin and script-friendly.
mkdir -p /root/binCreate your personal command directory.
PATH="$PATH:/root/bin"Append a directory for this shell.
echo 'export PATH="$PATH:/root/bin"' >> /root/.profileMake it permanent.

Quiz

  1. `PATH=/bin:/usr/bin` and both contain a file `tool`. Which runs when you type `tool`?

    • /bin/tool
    • /usr/bin/tool
    • Both, one after the other
  2. Which line adds /root/bin without losing the existing directories?

    • `PATH=/root/bin`
    • `PATH="$PATH:/root/bin"`
    • `PATH+/root/bin`
  3. You installed `/root/bin/hello` with `chmod +x`, but `hello` says `not found`. Most likely?

    • /root/bin is not in PATH in this shell.
    • Commands must end in .sh.
    • Root cannot run its own scripts.
  4. Why is putting `.` in PATH a bad idea?

    • It makes the shell slower.
    • A malicious file with a common name in the current directory could be run by mistake.
    • It is not allowed by the kernel.
  5. Which is best inside a script to test if a command exists?

    • `command -v name >/dev/null`
    • `ls name`
    • `echo $name`

Practice

  1. Install a command called `hello`: an executable script `/root/bin/hello` (with a `#!/bin/sh` shebang) that prints exactly `Hello from /root/bin`.

  2. Make `/root/bin` part of `PATH` for every future login by adding a line to `/root/.profile`. Keep the existing directories: `ls` must still work.

  3. Find out which file runs when you type `awk` and save that full path (just the path) into `/root/lab/l93/where.txt`.

Open this lesson in the app to do the tasks in a real Linux machine and have them checked.