Linux keyboard.

Bob's Blog

How to Start Writing Scripts

Someone recently asked me, "How can I learn to write scripts?"

I think that they thought that they would have to do some study first. No, it's easy to get started, you could do that right now!

Were they asking about shell scripts? That is, Bash scripts? Or were they asking about some other scripting language such as Python? I didn't know, but that didn't really matter. The first thing that I told them was that it was easy to get started. Then I asked them about the specific scripting language they were interested in.

In an earlier article I explained how the command-line interface is so powerful, and how it's actually an interactive programming environment. If you know just enough to use the command line, or the "shell", then you're ready to start writing some simple scripts.

I've been using the UNIX family of operating systems since the mid 1980s, almost a decade before the first release of Linux, and I still learn something new from time to time. There's no need to wait until you think you know how, let's get started!

We Need An Excuse — What Shall We Do?

Let's say that you frequently wonder what time it is, both the current date and time, and where that is within the month. There are commands for that, try typing these:

$ date
Sat May 13 08:38:50 EDT 2023
$ cal
      May 2023        
Su Mo Tu We Th Fr Sa  
    1  2  3  4  5  6  
 7  8  9 10 11 12 13  
14 15 16 17 18 19 20  
21 22 23 24 25 26 27  
28 29 30 31           

Something that I learned only recently is that the cal command has an option to show a span of three months — the current month along with the month before and the month after.

$ cal -3
                            2023
       April                  May                   June          
Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  
                   1      1  2  3  4  5  6               1  2  3  
 2  3  4  5  6  7  8   7  8  9 10 11 12 13   4  5  6  7  8  9 10  
 9 10 11 12 13 14 15  14 15 16 17 18 19 20  11 12 13 14 15 16 17  
16 17 18 19 20 21 22  21 22 23 24 25 26 27  18 19 20 21 22 23 24  
23 24 25 26 27 28 29  28 29 30 31           25 26 27 28 29 30     
30                                                                

To see the choices:
$ timedatectl list-timezones

Let's say that you have a friend who lives in New Orleans, which is in the Central time zone of North America, and you want to know what time it is there. Your shell interface has an environment in which several variables should be set to appropriate values. One of those is TZ, the time zone. It should be set for wherever your computer is. But you can ask the shell to run just one command with that one variable set to something else. Look at what happens, this is about an hour earlier and it shows "CDT" instead of "EDT" as it does by default for me. If you actually live in the Central time zone, you could use "America/New_York", or "Europe/Paris", or "Asia/Saigon", or any valid time zone name.

$ TZ=America/Chicago date
Sat May 13 07:40:11 CDT 2023

And so, let's say that you think it's useful, or interesting, or at least it's an adequate excuse for learning how to write a script (play along here), to run a command to show the current date and time, then a command to show a three-month calendar, and then a command to show the time in New Orleans.

$ date
Sat May 13 08:41:29 EDT 2023
$ cal -3
                            2023
       April                  May                   June          
Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  
                   1      1  2  3  4  5  6               1  2  3  
 2  3  4  5  6  7  8   7  8  9 10 11 12 13   4  5  6  7  8  9 10  
 9 10 11 12 13 14 15  14 15 16 17 18 19 20  11 12 13 14 15 16 17  
16 17 18 19 20 21 22  21 22 23 24 25 26 27  18 19 20 21 22 23 24  
23 24 25 26 27 28 29  28 29 30 31           25 26 27 28 29 30     
30                                                                
$ TZ=America/Chicago date
Sat May 13 08:41:50 EDT 2023

However, that's quite a bit of typing, and you have to remember and accurately type several things:

Let's make this easy by writing a script!

How to Start Creating and Naming It

Back in the day at Purdue University, the professor quickly explained the ed editor on the first day of the first class that used UNIX, and then later said "There's a much better but much more complex editor named vi and here's a handout about it." Yes, really. Today there's the vimtutor program for learning vim, the successor to vi, and there's an O'Reilly book you can buy used from Amazon.

A script is just a text file, you create it and modify it with your favorite text editor. nano and pico are very simple and easy to use. Personally, I prefer the much more powerful vim editor, but it's an awfully overwhelming place to start.

Now, you'll need to give your script file a name. It can be almost anything, but you're writing a script to make things easy. Don't give it a weird name that makes it difficult to use. Don't use any punctuation marks other than a dash, an underbar, or a period, and don't include white space.


Amazon
ASIN: 1492078808
Screen shot from the movie 'Arrival' altered to show the main character explaining how to exit the vim editor.

The operating system comes with very useful commands named time and date, so don't use those names. Since the purpose of your script is to check the time, maybe you want to name it checktime, or maybe check-time. Or maybe you want to follow the UNIX family tradition of short and easy to type (and sometimes hard to remember) names, and you'll use ct. That name isn't used, at least not on my system.

Of course, keep in mind that I've been using the UNIX family of operating systems since a decade before Linux was first released.

My personal preference is that everything should be all lower-case unless it somehow needs to be different, and it very seldom if ever really needs to be different. Why press more keys than absolutely necessary? But I know that other people feel, some of them quite strongly indeed, that a name formed of multiple words strung together should be in what's often called "Camel Case", and so checkTime instead of checktime.

Meh. Whatever. Any of those potential names will work. Pick whatever you want and start editing your new shell script file!

There actually is a ct() system call, but there is no ct command. If you're just now learning about writing shell scripts, don't worry about these details and feel free to name yours ct!

You might ask, "Don't I have to give my script a name that ends '.sh'?"

No. This isn't Windows. You can name a file whatever you want. The only thing that will pay attention to file name extensions will be some graphical desktop tools that try to emulate Windows. You can name your script file checktime.sh if you want, but there's no need, and that has no advantage over simply checktime. To me, a disadvantage is that you would always have to always type the added .sh, at least until you realized that Bash does command completion in addition to filename completion — the <Tab> key is your friend!

As you start creating your file, the one thing you must do is to make its first line explain what the file is. As we're creating a Bash shell script, make its first line contain exactly this:

#!/bin/bash 

You will find that some people refer to this as "the shebang line". I mention that to help you make sense of what you may read online. I'm not saying that you necessarily need to call it that yourself. I'm being descriptive but not prescriptive as linguists would describe things. Some people say it, do what you want.

That is, a hash character "#", and an exclamation mark "!" (which some people pronounce "bang"), and then the full path to the program that should interpret the following script. Since we're writing a Bash shell script, in this case that program is /bin/bash. If you were writing a Python script, it would start #!/bin/python or maybe #!/bin/python3 and so on.

Advanced topic: On FreeBSD the Bash shell isn't part of the base installation. You add it as a package and it's installed as /usr/local/bin/bash. But if you're already using FreeBSD, then you probably already know about shell scripts.

Creating Your Script

Now you simply put the sequence of commands into the file, one line for each command. You can add blank lines to make it easier to read.

Comments can make it easier to understand. Everything from a "#" character to the end of a line is there for humans to read, the shell will ignore it.

If you want to be somewhat fanatical about saving space, even though there's no real cost of how many characters are in a shell script, you could make your script look like this:

#!/bin/bash
# This is my script for checking the date and time.
date	# Output the date and time in the local timezone.
cal -3	# Display calendar for last month, this month, and next month.
TZ=America/Chicago date	# Output the date and time in the Central Time Zone,
			# used in Chicago and also New Orleans.
			# Running "date" command with environment
			# variable "TZ" changed to America/Central. 

Or, to be less fanatical and more readable, at least according to my personal tastes:

#!/bin/bash

# This is my script for checking the date and time.

# Output the date and time in the local timezone.
date

# Display calendar for last month, this month, and next month.
cal -3

# Output the date and time in the Central Time Zone, used in Chicago and New Orleans.
# Running "date" command with environment variable "TZ" changed to US/Central.
TZ=America/Chicago date 

Neither is more correct or appropriate than the other. It's just a matter of personal style and taste. Or maybe you work somewhere that imposes a corporate coding style. If so, do what they tell you to do.

How to Install and Run Your Program

You have to tell the operating system to treat your new script file as executable. That's the "x" bit you see reported in detailed listings.

$ ls -l check-time
-rw-rw-r-- 1 cromwell cromwell 387 May 13 08:57 check-time
$ chmod +x check-time
$ ls -l check-time
-rwxrwxr-x 1 cromwell cromwell 387 May 13 08:57 check-time*

Notice that the mode changed from 664 to 775, and now three x's appear for the user who owns it (you), the group that owns it (you should be the only member), and all other users.

Depending on how your system is set up, your ls may be defined as an alias which does the normal listing but also uses text color and a few appended punctuation marks to indicate directories, symbolic links, and files with particular content types, or which are executable.

Now you seem to be ready to run it, but it will probably fail like this:

$ check-time
check-time: command not found

What? You're certain that you spelled it correctly, and just turned on the executable bits. What's wrong?

Your PATH environment variable probably does not contain ".", the current directory. There's a security risk associated with doing that, so distributions don't.

You can run your new program by specifying exactly where it is and what it's named. Since I'm assuming that you started playing along with this story in your home directory, any of the following could work because "~" means your home directory, which is under /home:

$ ./check-time
[... output appears here ...]
$ ~/check-time
[... output appears here ...]
$ /home/yourlogin/check-time
[... output appears here ...]

However, the people who built your Linux distribution assumed that you very likely would start writing your own programs. So, they probably will have set up your PATH to include something just for you. See what yours is:

$ echo $PATH
[... one long line appears here ...]

The long line contains several entries separated by colons or ":" characters. Look for something under your home directory, such as /home/yourlogin/bin. Create that directory if needed, and move your new script into it, changing the details of the following as needed:

$ mkdir /home/yourlogin/bin
$ mv check-time /home/yourlogin/bin

Now you're ready to run your new shell script, no matter where you are at the moment:

$ check-time
[... output appears here ...]

Congratulations! You have created and installed your own shell script!

Extending and Improving Your Script

You can use the echo command to provide narration. We're working on a very simple script with pretty obvious output, but let's see how to do that:

#!/bin/bash

# This is my script for checking the date and time.

# Output the date and in the local timezone.
echo "The current date and time, locally, is:"
date

# Display calendar for last month, this month, and next month.
echo "Here's the calendar for three months centered on now:"
cal -3

# Output the date and in the Central Time Zone, used in Chicago and New Orleans.
echo "Here's the date and time in Chicago (and New Orleans):"
TZ=America/Chicago date 

You might decide that your echo command strings provide adequate explanation within your script, and it's redundant to have comments and the echo strings. That's fine, whatever you think is best!

Where To Go From Here

As you become more familiar with the command-line interface, you will learn and come to appreciate various commands. You will start to think of them as verbs — you could sort the content of a file or a data stream to put it into forward or reverse alphabetic or numeric order. You could grep a file or a data stream to extract just the lines containing certain patterns. You could awk it to select just certain fields of certain lines, and output them in a rearranged order. You could sed a data stream to modify it, or apply that change to a file to modify its content without using an interactive editor.

As you become familiar with the environment, you will think about tasks in a sequence of three major stages:

  1. What sequence of processing steps is needed? Extracting just certain lines, then just certain fields out of those, sorting and counting and so on. You will need to think about this as a pipeline of processes, in which the output of one process becomes the input of the next process. Most of the fundamental UNIX-family commands are designed to support this.
  2. What sequence of commands could somehow carry out those conceptual tasks?
  3. Which specific options and syntax are needed to make that happen?

Then, if the overall task is something you anticipate wanting to repeat in the future, you can create a new shell script for it.

Shell scripts let you create arbitrarily complex tools to analyze patterns, calculate statistics, and generate reports about web server activity logs, security logs, and many more things of interest to security analysts, system administrators, web site administrators, and other.

I'll come back to this general topic from time to time, and show you example scripts providing answers for which I don't know of any pre-existing tools. But it's easy to write your own as a shell script! As I add suggestions and explanations, I'll add links to them here.

Next:

Learn How to Write a Shell Script to Analyze Logs
Write a shell script to analyze logs and generate a report. We'll start by reporting the web server's 20 most popular pages.

Latest:

What is "A.I.", or "Artificial Intelligence"?
So-called "A.I." is hype and misunderstanding, here's hoping the next "A.I. Winter" arrives soon.

Previous:

Why the Command Line Rules
Many tasks are much easier to accomplish from the command line. Some tasks can't be done any other way.

Which Programming Language Should I Learn?
Someone asked me, "Which programming language should I learn?" It depends on what you want to do.

Cybersecurity Certifications are Unfair
Cybersecurity certifications are not a fair test of knowledge, let alone skill. They have an illusion of relevance and meaning, making more money for the certifying companies.

How Not to Get a Job
In which I stumbled into a teaching job through mistaken identity, with the involvement of a doomsday cult.