Read

Module 9 · Shell scripting basics

Your first script: shebang, chmod +x, running it

Put commands in a file, tell the kernel which interpreter runs it, make it executable and run it the three different ways.

What you will learn

  • Explain what the `#!/bin/sh` line does and why it must be the first line.
  • Create a script, make it executable with `chmod +x` and run it with `./name`.
  • Tell apart `./script.sh`, `sh script.sh` and `. script.sh`.

Everything you have typed in the last eighty lessons was a tiny program that lived for one line. A shell script is just those lines saved in a file, so you can run them again, hand them to someone else, or schedule them. The shell reads the file top to bottom and executes each line exactly as if you had typed it. No compiler, no new language: it is the same ls, grep and | you already know.

The shebang line

The first line of a script should be #!/bin/sh. The two characters #! are nicknamed the shebang. When you run a file, the kernel looks at its first bytes; if it finds #!, it starts the program named right after it and passes the script as an argument. So ./hello.sh really becomes /bin/sh ./hello.sh. For the shell itself the line is only a comment (it starts with #), which is why it does no harm. The shebang has to be the very first line, with no blank line or space before it, or the kernel never sees it.

In this VM /bin/sh is BusyBox ash, a small POSIX shell. There is no bash here, so a script that starts with #!/bin/bash fails with not found. Writing plain POSIX sh is a good habit anyway: such scripts run on every Linux, on BSD and on macOS without changes.

Write, make executable, run

You can write the file with vi (lessons 28 and 29) or, for something short, with printf and a redirection. Then give it the execute permission with chmod +x (lesson 46) and run it with ./hello.sh. The ./ matters: the shell only searches the directories in PATH for commands, and your current directory is not one of them, so a bare hello.sh answers not found.

~% mkdir -p lab/l81 && cd lab/l81
l81% printf '#!/bin/sh\n# My first script\necho "Hello, TempMV"\necho "Today is $(date +%A)"\n' > hello.sh
l81% cat hello.sh
#!/bin/sh
# My first script
echo "Hello, TempMV"
echo "Today is $(date +%A)"
l81% ./hello.sh
sh: ./hello.sh: Permission denied
l81% chmod +x hello.sh
l81% ./hello.sh
Hello, TempMV
Today is Sunday
l81% ls -l hello.sh
-rwxr-xr-x    1 root     root            76 Oct  4 18:51 hello.sh

Three ways to run a script

CommandNeeds +x?Runs where
./hello.shYes; the shebang picks the interpreterA new shell process
sh hello.shNo; the shebang is ignoredA new shell process
. hello.sh (dot space)NoYour current shell: variables and cd stick

The first two start a child shell, so anything the script changes, a variable, the current directory, disappears when it ends. The third form, called sourcing, runs the lines inside your own shell; it is how /etc/profile is loaded at login, and it is what you want when a file only defines variables or aliases.

Comments start with # and run to the end of the line. Use them: a script you wrote three weeks ago is a script written by a stranger. The .sh suffix is a convention for humans, not a rule for the kernel; the shebang is what decides.

Commands in this lesson

CommandWhat it does
#!/bin/shShebang: first line, names the interpreter.
chmod +x script.shMake the file executable.
./script.shRun a script from the current directory.
sh script.shRun it with an explicit interpreter; no +x needed.
. script.shSource: run the lines in the current shell.
echo $?Exit status of the last command (126, 127…).

Quiz

  1. What does the line `#!/bin/sh` do?

    • Tells the kernel which program should interpret the file.
    • Makes the file executable.
    • Prints the shell version.
  2. `./hello.sh` prints `Permission denied`. Most likely cause?

    • The shebang is wrong.
    • The file lacks the execute bit; run `chmod +x hello.sh`.
    • You are not root.
  3. Which way of running a script keeps its variables in your current shell?

    • `./script.sh`
    • `sh script.sh`
    • `. script.sh`
  4. Why does typing `hello.sh` (without `./`) fail even after `chmod +x`?

    • The shell only looks for commands in the `PATH` directories, not in the current one.
    • Scripts must always end in `.sh` and be in /bin.
    • `chmod +x` only works on binaries.

Practice

  1. Create an executable script `/root/lab/l81/hello.sh` with a `#!/bin/sh` shebang that prints exactly `Hello, TempMV`.

  2. The script `/root/lab/l81/report.sh` exists but `./report.sh` says `Permission denied`. Fix it so it can be run directly.

  3. Run `/root/lab/l81/report.sh` (it is not executable, so use `sh`) and save its output into `/root/lab/l81/out.txt`.

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