Bash scripting
A Bash script is a text file of commands that Bash runs top to bottom, so a job you type every day can run itself. Follow one seven-line script, count.sh, as it runs: the kernel reads the shebang and starts bash, a variable is made, a glob turns *.txt into a list of file names, a for loop walks that list while arithmetic counts, echo prints each result, and the script ends with an exit status.
5 quick questions
Pick an answer to see why. Your score saves with your progress.
01What does the first line #!/bin/bash do?
When you run ./count.sh, the kernel reads the #! line and starts the interpreter it names, /bin/bash, with the script's path. To bash itself the line is just a comment. Making the file executable is chmod +x's job.
02Which line correctly sets a variable named count to 0?
No spaces around the =. With spaces, Bash reads count as the name of a command to run with the arguments = and 0, which fails.
03A folder holds hello.py, notes.txt and todo.txt. What does for f in *.txt loop over?
Bash expands the glob *.txt to the names that end in .txt, sorted: notes.txt then todo.txt. hello.py does not match. If nothing matched, the loop would see the text *.txt itself (unless nullglob is on).
04count holds 1. What does count=$((count + 1)) leave in count?
$(( )) is arithmetic expansion: Bash works out 1 + 1 and puts 2 in its place, so the line becomes count=2.
05Right after a script finishes, echo $? prints 0. What does that mean?
$? holds the exit status of the last command. 0 means success and any other number means failure. A script's status is the status of the last command it ran, unless it calls exit with a number.
Glossary
- Script
- A text file of commands that a program such as Bash runs from top to bottom.
- Shebang
- The first line of a script, #! followed by a path such as /bin/bash. It tells the kernel which program runs the file.
- chmod +x
- A command that gives a file execute permission, so you can run it as ./name.
- Variable
- A name that holds a value inside the running bash, made with name=value and read with $name.
- Glob
- A pattern with wildcards, such as *.txt. Bash replaces it with the sorted list of file names that match.
- for loop
- for name in list; do ... done runs the lines between do and done once for each item, with name set to that item.
- Arithmetic expansion
- $(( expression )): Bash works out the sum (whole numbers only) and puts the answer in its place.
- Exit status
- A number a command returns when it ends: 0 for success, 1 to 255 for failure. $? holds the last one.
Notes and sources
- Some scripts start with #!/usr/bin/env bash instead, which finds bash wherever it is installed. You can also run a script without chmod +x by typing bash count.sh.
- Bash sorts the names a glob expands to using your locale's order. If no file matches, the pattern stays as it is (the loop would see the text *.txt) unless you turn on shopt -s nullglob.
- $(( )) works with whole numbers only. Bash variables are text by default; inside $(( )) Bash reads them as numbers.
- A script's exit status is the status of the last command it ran, here echo, which returned 0. Use exit 1 to report a failure yourself.
- GNU Bash Reference Manual
- GNU Bash manual: 3.8 Shell Scripts (#! and chmod +x)
- GNU Bash manual: 3.2.5.1 Looping Constructs (for)
- GNU Bash manual: 3.5.8 Filename Expansion (globs)
- GNU Bash manual: 3.5.5 Arithmetic Expansion
- GNU Bash manual: 3.7.5 Exit Status
- Linux man-pages: bash(1)
- Linux man-pages: execve(2), interpreter scripts (#!)
- Linux man-pages: chmod(1)
- Linux man-pages: glob(7), wildcard matching
- Linux man-pages: echo(1)
- Debian Policy Manual: 10.4 Scripts
Quiz Unlocks after the last step.