As we get into more complicated computing tasks, the commands will be too numerous and verbose to type in manually and execute line-by-line – remember that once you've hit Enter, you can't go backwards at the interactive prompt.
So this is where we learn a new technique: writing shell scripts. Instead of typing a series of commands into the command-line interpreter, we type them into a text file. We then save that text file. And then we tell bash to execute the commands that are in that text file. which we refer to as a script.
Pretend that the file
my_script.sh contains the following commands:
echo "Hello there" echo "My name is $(whoami)" echo "Nice to meet you"
Executing that script involves invoking the bash program at the command-line and giving it the name of the script,
user@host:~$ bash my_script.sh Hello there My name is dun Nice to meet you
A brief segue here: We can (and sometimes do) create quickie text files from the command-line. To create the aforementioned
my_script.sh, for example:
user@host:~$ echo 'echo "Hello there"' > my_script.sh user@host:~$ echo 'echo "My name is $(whoami)"' >> my_script.sh user@host:~$ echo 'echo "Nice to meet you"' >> my_script.sh
Did that look ugly and awkward? That's because it is. And it's prone to all the problems you have before, in which one typo on a previous line will cause you to start all over again.
To open nano, simply type in nano at the prompt:
However, I like passing in the name of the file that I intend to create. By default, nano will choose that argument as the filename to save to. If that filename already exists, nano reopens the file for editing.
user@host:~$ nano myfile.txt
Either way, nano is a servicable text editor. Sure, it'll feel primitive compared to anything you've used since, say the Apple ][…but it's significantly more comfortable and forgiving than the prompt. You can move up and down previously-entered lines of text, for example.
When you're done entering in commands (or whatever you want, it is just a text editor, after all), hit Ctrl-X to exit. nano will then ask you, in the most confusing way possible, if you want to save your changes. Type
y, which should then prompt
nano to specify the filename. Hit enter, and you'll be back at the prompt.
Here's an animated GIF of me creating a script by entering nano, writing out the commands, saving it, and then executing it from the prompt:
my_script.sh seems lame, that's because it is. The commands it runs are simple. And every time we run it, it does the same thing.
What if we made a more friendly version of it? We'll call it,
my_friendly_script.sh. And this is how it should be used:
user@host:~$ bash my_friendly_script.sh Pat Hello there, Pat My name is dun Nice to meet you, Pat
See how the script adapted to the presence of
Pat? Or to any other name we give it? Having our script do different things based on command-line arguments is the first step to making it more reusable.
So, when editing the code that's in
my_friendly_script.sh, how do we refer to what was passed as a command-line argument, i.e.
By convention, special variables, or parameters, are reserved for command-line arguments:
1 is for the first argument,
2 is for the second, and so forth.
So to print
Pat to standard output, we refer to
echo "Hello there, $1" echo "My name is $(whoami)" echo "Nice to meet you, $1"
Read the tutorial, How to run a process in the background
The immediate benefit of turning one of our plain old shell scripts into an executable shell script is this difference in running the script:
Instead of this syntax:
user@host:~$ bash my_script.sh
We can simply do this:
In fact, let's try the above command for executing
my_script.sh: the prepending of the
./ is how we tell Bash, run this
my_script.sh (and not another executable
my_script.sh somewhere else in the file system):
user@host:~$ ./my_script.sh -bash: ./my_script.sh: Permission denied
OK, bash didn't like that. What does permission mean? As you've seen yourself, the
my_script.sh file is simply a text file, with no real powers over any other collection of plaintext, until we pass it as an argument to
bash, in which case, the
bash program executes the text as commands.
Contrast that with
echo, which is more than just a text file, but more relevant to our topic, has permission to__ execute. As soon as we type
echo and then hit Enter, a _program actually runs. There's no need to tell
bash, "Hey, can you read this word of text I wrote, and then execute it as a program?"
We want that kind of authority, that permission to execute, for my_script.sh.
And this is how we do it:
user@host:~$ chmod a+x my_script.sh
And that's it. Read more about the chmod command on your own, if you'd like. But we can now try to execute
my_script.sh without explicitly invoking bash:
user@host:~$ ./my_script.sh Hello there My name is dtown Nice to meet you
We can even rename
my_script.sh to just
my_script to give it more of an elite look, and because bash honestly doesn't care what you name your files or what extensions you give it:
user@host:~$ mv my_script.sh my_script user@host:~$ ./my_script Hello there My name is dtown Nice to meet you
What about that
./ that we have to include? We can remove that to, by moving
my_script into a directory that's part of the bash environment's executable
PATH. You can read more about that here.
Because we're executing
my_script in the Bash shell, by default, bash is implicitly invoked to interpret the commands inside
However, later on, when we create scripts in the Python language to execute from Bash, we need to specify in the very first line of the script: we want to use Python to run this script. So when we run that Python script, the Bash interpreter reads that line and knows, "This script is meant to be run by the Python interpreter, so I'll pass it along"
That first line that says, "Hey, use this program to interpret what's in this script", that's called the shebang.
And for scripts that are meant to be run by bash, it looks like this:
Again, it's optional to add to our
my_script. But it's a good habit to get into.
Software Carpentry has a great guide on shell scripts.
Check out the class textbook for more details on creating reusable and executable scripts.