Bash Scripting with CLI

Add more tools to your command line arsenal, including running mini-scripts and making backup copies.

So far in this series we’ve spent some time talking about how to use the command line to do things like how to chain commands together and do basic file system tasks. Now we’re ready to talk about writing programs for the command line!

If you have a Mac or a Raspberry Pi, look for the Terminal application. If you’re on Windows 10, you’ll want to follow the steps in the following article on how to set up a terminal with bash on Windows!

Now, this isn’t the old-school command line for Windows. That’s a program called Powershell. Powershell is a bit different than anything else, so we’ll cover it separately in the future.

First, let’s throw out a couple of definitions that are relevant. The program that you’re interacting with when you’re on the command line is a shell. The shell is what interprets the commands you type and turns them into commands the operating system understands.

There’s quite a few shells that exist but the one that is used by default on Linux and OSX is bash. So bash stands for “Bourne Again SHell”, and it’s named this because it’s a revamp of an even older shell program called the “Bourne shell” that dates back to the 1970s. By comparison, bash is a spry 29 years old.

A cool thing about shells like bash is that they have their own programming language built in. For example, here’s a tiny little script to play entire directories of music from the Raspberry Pi I have hooked up to some speakers:

for song in "$dirName"/*.mp3
	omxplayer "$song"

This is small and simple but all the elements of bash scripting are here: variables, loops, command line arguments, and calling other programs. You might be able to sound out this example.

You’re creating some kind of variable that stores the directory name. Then for every song, which is a file in the directory that ends in .mp3, run the program omxplayer — which is the main music and video program for the Raspberry pi—on that song to play it.

Now, let’s cover those topics by going through a few examples you can try out for yourself..
The very first thing we’ll cover is reading in command line arguments. By “command line arguments” I mean something like the file and directory names in:

mv fatdog.mp3 dogthemedsongs/

The command is mv and fatdog.mp3 and dogthemedsongs/. are both arguments.

If you’re writing a bash script you can read the command line arguments as $1, $2, $3, etc. for the first, second, third, and other arguments. To test this out, let’s do a little bash script version of “Hello World”. We’ll use the nano editor and type a few commands:


In the nano editor, type this text:

echo “Hello” $1

Next, press the Control key and type X to exit nano. Type Y and press enter to save the file.

Now we need to make the file executable by the bash command line software, to tell the operating system “yes, I want to run this as a program”:

chmod +x

And, finally, let’s feed our little program a word:

./ world

Your command line software should output “Hello world” If you try this, what happens?

./ fred

In the file, $1 is the value we pass into the script. The value is added to “Hello” with a space between that word and the $1.

Now, what the heck is this #!/bin/bash business that’s at the top of the script? That makes sure that your operating system knows to treat this program as a bash script and feed the text of the code into the bash program to run it.

Below that, we use the echo command which prints whatever string you give it. In our hello world program, we give it “Hello” and the first command line argument.


Okay, so that’s not very interesting. What else could we do? Well, a really easy program would be a “backup” program that makes backup copies of all the files in whatever directories you give it. Open a file called and type in the following:

for dir in $@
    for file in $dir/*
	cp $file ${file}_backup

Let’s talk out what’s happening in this program.

The first thing to discuss is how for loops work in bash. If you’ve played around with Python before, this kind of for … in loop might look familiar. It’s how you do something, you iterate over every element in a list of data. Every go-round of the loop it puts the next element on the list in the loop variable, which is dir for the outer loop.

What’s the list in the first loop? It’s a special variable called @ which is a list of all the command line arguments you gave the program when you ran it. In our case, it’ll be all the directories you want to backup. In the second loop, the list you’re iterating over is every file in the directory stored in the variable dir. To get the value stored in the variable dir you need to put a $ in front of the variable name. So if you ran this program like:

./ my_stories

The first time the loop runs dir is going to have the value my_stories. This means that the expression $dir/* will have the value my_stories/*, which we know from our prior experiments on the command line means “every filename that is in the directory my_stories”. In this example, the inner loop will go through every file in the directory my_stories and then copy that file to a new file with the same name but _backup stuck on the end.

So if there was a file called TheFattestDog.txt in the directory my_stories this program would copy it to a file called TheFattestDog.txt_backup. Why do we need those curly-brackets around ${file}, though? Bash needs to distinguish between a variable called file and a variable called file_backup in this case, so the curly brackets are a way of telling bash “no, the variable is called file and I want to stick ‘backup’ to the end of whatever string is stored in file.”

Okay, now you have a program that can make backups. What about making a program that restores the old backup in the directory? We can do that by just some slight modifications of our previous code!

for dir in $@
    for file in $dir/*_backup
	cp $file ${file%_backup}
	rm $file

The big thing that’s different is the line that says ${file%_backup}. Bash has a lot of built in things to help deal with file name manipulation: it’s a programming language for administering computers, after all! This is one of the more unique ones. What ${name%text} means to bash is “take the string stored in the name variable and remove text from the end of the string.” So in our program it removes the _backup from filename. In fact, the %operator is a lot more powerful than that: you can cut the part of the file name that matches any regular expression you give it, if you happen to have learned what those are.

That’s our first intro to making a real command line utility as a bash script! It’s actually pretty useful, though no replacement for real version control like git.

Next time, we’ll be talking more about bash scripting, the cron utility, and more about secure shell to control other computers and administer them. Until then, try playing around on the command line and coming up with tasks you might want to automate or fun things to try. There’s so much you can do in bash with just what we’ve covered so far.

Learn More


The command line has a programming language built into it so you can write programs that behave like the built in commands.

A long-form tutorial on bash scripting

Another longer guide to bash scripting

An alternative to bash


  • Clarissa Littler

    Clarissa has worked in mathematics, physics, and computer science research but spends much of her time now trying to make computer science education accessible to a broader audience.

Also In The October 2018 Issue

Logic puzzles help develop reasoning skills useful for programming, computer science, and anything you might do.

Find perfect and fun gifts for your loved ones that teach STEAM concepts and skills.

From light-up bow-ties to conductive thread, you’ll be the life of the party with this STEAM-inspired gear.

A free online test service reveals how much personal data your web browser is giving away.

Add more tools to your command line arsenal, including running mini-scripts and making backup copies.

Use switches to take your robotic creations to the next level.

An old classic with a electronic twist, featuring JavaScript and micro:bit.

Create the American flag in SketchUp using this detailed tutorial.

From lasers to supernovas, Berboucha is making science communication a priority.

Code can always be improved. Check out these tips to make you the best programmer you can be!

It’s a programming language unlike any you’ve seen before. Check out this symbolic system designed for mathematical calculations.

New, improved, faster, and sleeker - it’s Scratch 3, your new favourite block language!

Learn about the brilliant algorithm behind all of your GPS devices.

It’s free, comprehensive, and available on-the-go. This cool app helps you master Python faster than ever before.

Open up whole new worlds to explore through these interesting, diverse add-ons.

Links from the bottom of all the October 2018 articles, collected in one place for you to print, share, or bookmark.

Interesting stories about computer science, software programming, and technology for October 2018.

Interested but not ready to subscribe? Sign-up for our free monthly email newsletter with curated site content and a new issue email announcement that we send every two months.

No, thanks!