Never written a script? This page is the shortest path to a first Bash script that works: a file, a shebang line, the execute permission, and it runs. In a few minutes, you will know how to create, make executable and run a script, with variables and arguments, with no programming background at all. For conditions, loops and functions, the complete Bash shell scripting guide takes over.
What you will learn
- Create a script with the shebang
#!/bin/bash - Make it executable with
chmod +x - Use variables to store values
- Read user input with
read - Get the arguments passed to the script
- Exit cleanly with an exit code
How do you create a minimal script?
A script is nothing more than a text file holding the commands you would
have typed by hand. The 5 steps below produce a complete one, and two of
them often surprise people: the file must receive the execute permission,
and running it takes a ./ in front of its name.
-
Create a file named
hello.sh:Terminal window nano hello.sh -
Write this content:
#!/bin/bashecho "Hello, welcome to $(hostname)!" -
Save and exit (Ctrl+O, Enter, Ctrl+X).
-
Make the file executable:
Terminal window chmod +x hello.sh -
Run the script:
Terminal window ./hello.sh
Hello, welcome to server01!What is the shebang?
The first line of a script must be the shebang, which names the interpreter that will read the rest of the file:
#!/bin/bashIt tells the system which interpreter to use to run the file. Without this line, the kernel does not know that it is a Bash script.
How do you make a script executable and run it?
By default, a new file is not executable. Two steps are
needed, chmod +x then the launch with ./:
chmod +x my-script.sh./my-script.shThe ./ tells the shell to look for the file in the current directory, instead of the directories of the PATH.
There is an alternative, useful when you are not allowed to change the file's permissions: call Bash directly on the script.
bash my-script.shThe interpreter is then chosen by the command, not by the shebang,
which is simply ignored. It is handy for a quick test, but the standard
method remains chmod +x followed by ./my-script.sh: it makes the script
usable like any other command.
How do you use variables?
A variable stores a value so you can reuse it, and $(...) fills one with the output of a command:
#!/bin/bashNAME="Alice"MACHINE=$(hostname)echo "Hello $NAME, you are on $MACHINE"Three rules apply, the same as on the command line:
- No spaces around the
= - To read the value:
$NAME $(command)captures the result of a command
Naming good practices
These conventions are not enforced by Bash, which would accept far worse: they exist so that the script stays readable months later, by you or by someone else. The most rewarding is the second one, a descriptive name, because it removes the need to go back up the code to find out what a variable holds.
| Convention | Example |
|---|---|
| Upper case for global variables | DIRECTORY, FILE_NAME |
| Descriptive name | LOG_FILE rather than F |
| No special characters | Only letters, digits, _ |
How do you read user input?
The read command pauses the script and waits for the user to type
something:
#!/bin/bashecho "What is your first name?"read FIRSTNAMEecho "Hello $FIRSTNAME!"To show the message and the input on the same line, use read -p with the prompt text:
read -p "Your first name: " FIRSTNAMEecho "Hello $FIRSTNAME!"How do you pass arguments to a script?
A script can receive values when it is launched, written after its name:
./greet.sh Alice BobThese values are available through special variables, numbered in the order of the arguments:
| Variable | Contents |
|---|---|
$1 | First argument (Alice) |
$2 | Second argument (Bob) |
$# | Number of arguments (2) |
$@ | All the arguments (Alice Bob) |
$0 | Name of the script (./greet.sh) |
A complete example, which prints each variable in turn so that you can see what it contains:
#!/bin/bashecho "Script: $0"echo "Argument 1: $1"echo "Argument 2: $2"echo "Number of arguments: $#"Check that an argument is given
A robust script checks that the arguments it needs are present, and stops with a usage message otherwise:
#!/bin/bashif [ -z "$1" ]; then echo "Usage: $0 <name>" exit 1fiecho "Hello $1!"-z "$1" tests whether the first argument is empty. If so, the script
prints a help message and stops.
How do exit codes work?
Every command (and every script) returns an exit code. Three values cover the needs of a first script:
| Code | Meaning |
|---|---|
0 | Success |
1 | General error |
2 | Misuse (wrong arguments) |
To end a script with a given code, use exit followed by the number:
exit 0 # everything went fineexit 1 # an error occurredTo check the exit code of the last command, print $? right after it:
echo $?How do you write comments?
A comment starts with #. The shell ignores everything that follows on the
line:
#!/bin/bash# This script prints a welcome messageNAME="Alice" # Variable holding the first nameecho "Hello $NAME"Comment your code to explain why you do something, not what (the code already shows that).
Complete example: system report
Here is a concrete script that gathers information about the system, then the two commands that run it:
#!/bin/bash# system-report.sh: shows a summary of the system state
echo "=== System report ==="echo "Date : $(date)"echo "Machine : $(hostname)"echo "User : $USER"echo "Directory: $PWD"echo ""echo "Disk space:"df -h /echo ""echo "Memory:"free -hecho "=== End of report ==="chmod +x system-report.sh./system-report.shThis script only chains commands you already know. That is the principle of a script: automate a sequence of repetitive tasks.
Troubleshooting
The failures of a first script all look alike: the file is there, its
contents are correct, and nothing runs. Three causes cover most cases, a
missing execute permission, a forgotten ./ in front of the name, and
a file saved with Windows line endings. None of them concerns the code
itself.
| Symptom | Likely cause | Fix |
|---|---|---|
Permission denied | Script not executable | chmod +x my-script.sh |
command not found when running script.sh | ./ missing in front of the name | Run it with ./script.sh |
cannot execute: required file not found | Wrong shebang or Windows characters (CRLF) | Check #!/bin/bash on the first line, convert with dos2unix |
| Empty variable in the script | Wrong name or $ forgotten | Check the exact name and the $ in front |
[-z: command not found | Missing space after [ in the test | Write [ -z "$1" ] with spaces |
| Script that never stops | Implicit loop or read waiting | Ctrl+C to interrupt |
The bad interpreter message no longer exists
If you are looking for bad interpreter: No such file or directory, the
message most tutorials still show, you will not find it.
Bash 5.2 changed the wording, and it is now the same message for a
wrong shebang and for a file saved with Windows line endings:
bash: ./my-script.sh: cannot execute: required file not foundThe exit code is 127. The cause stays the same: the kernel cannot find
the interpreter given after the #!. In the CRLF case, the interpreter looked
for is literally /bin/bash\r, with an invisible carriage return at the
end, hence a file "not found" although /bin/bash does exist.
file my-script.sh # "with CRLF line terminators" gives the culprit awaydos2unix my-script.shPut it into practice
You only understand a script by writing it yourself, then running it on real data. This lab has you produce a report.sh that reads a status file passed as an argument, counts the UP/DOWN hosts with a loop and a condition, then returns a non-zero exit code as soon as a host is down. Your script is compared with the expected behaviour.
Key points
- A script starts with
#!/bin/bash(the shebang), which identifies the interpreter. chmod +xmakes the file executable,./script.shruns it.- Variables (
NAME="value") and arguments ($1,$2) make a script flexible. readasks for input,echoprints a result.exit 0signals a success,exit 1an error, which you can test withecho $?.- Comment your scripts to make them understandable.
Knowledge check
Check that the essentials of this guide stuck. The questions cover only what has just been explained here.
Knowledge check
Check what you have learned with this interactive quiz
How it works
- The timer starts when you click Start
- Multiple choice, true/false and short answer questions
- You can move between questions
- Detailed results are shown at the end
Starts the quiz and the timer
Review
(0/0)Score by domain
A domain groups several guides and gets several questions, so its score is more reliable than a per-topic score, which often rests on a single question.
Summary
Strengths
No topic passed at 80% on at least two questions yet.
Weak areas
No topic below the pass mark.
Recommended next
Hints before you try again?
Continue the course: Linux users, permissions and processes
A new full quiz with random questions
Work again only on the questions you missed