OPS145 Lab 9 Newversion
Bash scripting
Bash is the shell you've been using in this course to run Linux commands. Bash is also a programming language. It's a special purpose programming language, not something you would write a graphical application in. What you do in a bash script is essentially the exact equivalent of what you would run at a terminal prompt - except you can run all your commands at once, instead of one at a time.
A bash script is a plain text file. The bash programming language is interpreted (as opposed to compiled) - meaning the code you write doesn't need to be compiled before you can execute it.
Setup
The setup for writing a bash script is minimal. You'll need to:
- Create the script in a plain text editor: either graphical or on the command line. Usually you save it with a .sh extension, though technically you don't have to.
- Make sure you (and anyone else you want to allow to execute the script) have read and execute permissions for the file.
- Add a shebang line at the top.
Permissions
Since bash scripts are interpreted (rather than executed outright): you can't actually execute a bash file. In order to execute the commands in a bash script: they need to be read, and interpreted, and executed, by the bash program.
That's why just giving a script execute permissions may not be enough to run it. You need to give yourself read permission, so that the bash program can read your script and execute it.
In fact you don't even need execute permissions to run a bash script. You can run bash, and give it the name of the script as the first argument.
Shebang line
Because bash scripts are interpreted, and extensions are mostly ignored in Linux: the shell you're using to execute your script needs to know what kind of script it is. There are many interpreted programming languages. If you don't make it clear what language your script is written in: there's a chance it will be misinterpreted.
A shebang line for a bash script looks like this:
#!/bin/bash
It has the be the first line in your script.
Anything following this line is regular bash.
hello.sh
Decide for yourself whether you can handle the bash learning in this lab while using vi. If you feel that's too hard: you can use a graphical text editor.
- Create the lab9 directory inside your home directory.
- Open a text editor and save an empty file into ~/lab9/hello.sh
- Add the shebang line at the top
- Look at the permissions for your file in a terminal. You'll find that by default you have read and write permissions, but not execute permissions. Give yourself execute permissions using one of these two commands
chmod a+x hello.sh # Add execute permissions for everyone, or: chmod 755 hello.sh # Set permissions to exactly this
- Run the script by specifying an absolute path, a relative-to-home path, or if your PWD is right: you can use the . special character as a shortcut:
/home/yourusername/lab9/hello.sh # Run first.sh using an absolute path ~/lab9/hello.sh # Run first.sh relative-to-home path ./hello.sh # Run first.sh from the PWD
Your script doesn't do anything yet: but if you get any errors: the script might be in the wrong place, or it might have the wrong permisions, or you're not executing it correctly.
echo
echo is an interesting command. Initially it may appear to do nothing of use, but with better understanding of how programming works it will make a lot more sense.
The echo command prints some output (via STDOUT) - whatever output you tell it to print.
For example: if you run this in a terminal:
echo Hello
it will print the word Hello. If you give echo multiple arguments: it will print them all, with one space in between each of them:
echo Hello there # Note the multiple spaces
Remember that in bash the arguments for a command are whitespace-separated. So it doesn't matter how many spaces you put between arguments to echo: they are still interpreted as separate arguments. If you want to include multiple words and all the spacing between them in echo's output: combine them all into a single argument by enclosing the entire string of text into quotes:
echo "Hello there" # Note the multiple spaces
The echo command can be used for more complicated things, but this is all we need for this lab.
- Add a line to your shell script so that when you run the script: it will print: "Hello. I will now do a bunch of stuff". It should look like this when you run it:
One of the main reasons shell scripts are exceptionally useful is that once you get your script to work: you don't need to worry about typos, command syntax, or even remembering how exactly the commands work.
The other big reason is: you don't have to retype your commands every time you want to run them.
This simple echo program is a great example of that. You can already see that typing the command to run the script is much shorter than the one echo line inside the script. Obviously the longer the script: the greater the probability you will make mistakes, and the more you'd need to type when you wanted those commands executed.
date
Another very simple command is date.
- Run date in a terminal. It will print the current date and time.
Using arguments you can change the format of the output, add or remove parts that you want or don't want to see. We won't need to do that but if you're curious: you can look at the man page for date, under the FORMAT section.
- Modify your script so that its output looks like this (except with the current date, don't hard-code the 25th of march in your script):
Re-running a script
A script is usually meant to execute unattended. Ideally your script will account for the most common variability in the environment.
For example: if you mean to create a directory in a script, and you run the script a second time: the script should not cause errors the second time because the directory was already created the first time. You should decide when you build the script how to deal with this possibility.
As an example: let's start with a script like this:
#!/bin/bash
mkdir ~/lab9/temp/
- Save that code as ~/lab9/lab9.sh and give it execute permissions.
- Run lab9.sh twice.
- Note that the first time you run it: it creates the temp directory. The second time you run it: you get an error.
Depending on the circumstances you might want to ignore the error, or make sure the directory is deleted before you attempt to create it, or you might actually want to get an error.
- In our case let's say we want a brand new, empty, temp directory created every time the script runs. To ensure that happens: delete the directory before you create it:
#!/bin/bash rm -r ~/lab9/temp/ mkdir ~/lab9/temp/
- Now you can run the script as many times as you want, and every time you will end up an empty temp directory.
This script still has some potential problems, but all of them are dealt with in the same way:
- Anticipate what could go wrong
- Structure your code to do something you want under different circumstances
lab9-dolab3.sh
We're going to write a script which will do all the command-line work you've done in lab 3, starting with the mkdir section.
- Create ~/lab9/lab9-dolab3.sh
- Your script has a PWD, no different than the interactive shell you've been using this whole time. If you want to run mkdir lab3-cmd and have that create lab3-cmd in your home directory: you need to change your PWD first:
#!/bin/bash echo "My pwd is now: " pwd cd ~ echo "My pwd is now: " pwd
- Note that even though inside the script the pwd was your home directory: once the script exits your PWD is set back to what it was before the script executed. That's because a new bash process is started when you run your script, and that new process exits when the script is done executing:
- Have a look at what's inside your ~/lab3-cmd now. If you finished lab3: you should have some subdirectories and files in there. Maybe make a backup copy of it, so you have something to compare your script's work to.
- We want this lab9-dolab3.sh script to do all the work, starting with creating lab3-cmd. So our script will delete lab3-cmd and all its contents before it does anything else. Try this:
#!/bin/bash echo "My pwd is now: " pwd cd ~ echo "My pwd is now: " pwd rm -r lab3-cmd
- Run the script twice. Note that the second time you get an error, because you are trying to delete a directory which is no longer there.
- You can fix that by adding the -f option to rm:
#!/bin/bash echo "My pwd is now: " pwd cd ~ echo "My pwd is now: " pwd rm -r -f lab3-cmd
- You can use a terminal or a graphical file manager to check on the results of running your script.
- The next few instructions we can copy verbatim from lab 3:
#!/bin/bash # Start in home directory cd ~ # Delete the lab3-cmd directory and its contents if it exists rm -r -f lab3-cmd # This way you make sure lab3-cmd exists and is empty mkdir lab3-cmd # These commands are copied verbatime from lab3: mkdir lab3-cmd/red cd lab3-cmd/red pwd mkdir ../green pwd ls ls .. # Make sure to replace youruserid with your user id: mkdir /home/youruserid/lab3-cmd/blue ls ~/lab3-cmd
- Note that when the script gets longer: it's helpful (for you) to have some comments in it explaining what you're intending the script to do.
- Also: you may get confused about which part of your script produces which output. In the latest we have it's not clear which is the output from ls and which from ls ..
- A common way to deal with this is to add some echos:
#!/bin/bash # Start in home directory cd ~ # Delete the lab3-cmd directory and its contents if it exists rm -r -f lab3-cmd # This way you make sure lab3-cmd exists and is empty mkdir lab3-cmd # These commands are copied verbatime from lab3: mkdir lab3-cmd/red cd lab3-cmd/red pwd mkdir ../green pwd echo "Contents of the directory above (red):" ls echo "Contents of the parent of that directory (~/lab3-cmd/):" ls .. # Make sure to replace youruserid with your user id: mkdir /home/youruserid/lab3-cmd/blue echo "Contents of ~/lab3-cmd/:" ls ~/lab3-cmd
- Let's skip the removing directories section of lab 3 since that doesn't leave anything for us to look at. We'll continue with the cp section.
- Add the first two commands from that section to your script and run it:
cd ~ cp Downloads/SampleFiles.tar.xz lab3-cmd/red
- Then check that your script did what it was supposed to. There are multiple ways to do that:
- Add the -v argument to cp. That way it will print what it's copying into where.
- Add a temporary ls command inside your script, to check that the new file has been copied to lab3-cmd/red successfully.
- Look in that directory outside your script.
When you write a long script: it's good practice to check that smaller parts of it work, rather than finish the whole script and then try to figure out at which point it didn't do what it was supposed to.
- Add the rest of the commands from the cp section to your script: so you'll end up with the same contents as you did at the end of that section in lab 3 (there's a screenshot there).
- Finally: add commands to your script to also complete the moving section and deleting section of lab 3.
What was the point?
You might be thinking: writing this script was not any easier than doing lab3 one command at a time. So what was the point? There are two:
- You needed an introduction to scripting, and with this one you were already familiar with the expected results.
- You don't write a script to execut it once. Imagine you had multiple machines, a hundred perhaps, and they all needed lab3 completed on them. Doing it one command at a time would take 100 times longer. Running the script 100 times would barely take any time at all.
time
There's a command in Linux called time. It doesn't give you the current time (the date command does that). The time command measures how long another command takes to run. For example, you can measure how long your new script takes to run:
time ./lab9-dolab3.sh
You can ignore the user/sys times. The "real" time is time as we humans experience it.
Submit evidence of your work
After you finish the lab: run the following commands to submit your work:
cd ~
wget http://ops345.ca/check/ops145-lab9-check.sh # Download the check script
chmod 700 ops145-lab9-check.sh # Make the downloaded file executable
./ops145-lab9-check.sh # Run the check script
If it says "Your lab9 has been submitted": make a screenshot, and you're done. If it gives you any warnings or errors: you have to fix them and try the ./ops145-lab7-check.sh command again.