How to Use the Terminal App for Shell Scripting on macOS

Dial in your shell scripting fundamentals for Mac with this helpful overview.

Terminal application for Mac

The Terminal application that ships with macOS is a powerful tool for controlling your Mac. But oftentimes less experienced users are reluctant to click into that powerful black box on their Mac monitor for fear of getting in over their heads and accidentally breaking something. Today, we’ll go over some basic information to get new Terminal app users started on the right foot.

First, we’ll take a look at how to execute some simple Unix commands from the Terminal directly, and then we’ll extend that understanding to allow you to link multiple Unix commands together in a text file generally referred to as a shell script.

These files are called shell scripts because they are comprised of a series of commands that are executed in something called a shell (that is powering the Terminal app). While there are a number of different varieties of shells that you may use on Mac, such as bash, sh and others, the default shell on Mac is zsh.

The differences between these various shells are obscure enough to largely gloss over here in this blog, but it is worth noting that each variety of shell reads its own set of environment definition scripts at machine startup and user login respectively. So, when you graduate to automating the execution of shell scripts in the Terminal, the shell type will become a more relevant consideration.

Understanding the Shell Environment

When you open the Terminal app, you’ll be met with a blank screen. But there is already information stored in this “environment” you’ve created and entered – in the form of environment variables – just by your having started the app. These variables are accessible from anywhere within the shell environment. This means that either a human user or a scripted process can access these bits of information as needed either directly from within the Terminal, or from a script that is called from the Terminal.

As an example, suppose you have a script that needs to connect to a third-party service like a database. You may elect to set a username and password for the database as environment variables for the script to read, so it doesn’t need to have sensitive information “hard-coded” into it.

To print the currently defined environment variables, you can type the following into the Terminal:

printenv

To set an environment variable for the first time, or to overwrite an existing variable, you can simply run:

export EXAMPLE_VARIABLE=1234

To access an environment variable, you can type a $ and then the variable name, like so:

$EXAMPLE_VARIABLE 
1234

Notice there is a standard format for writing environment variable names. It is not strictly required, but it is standard practice to name your environment variables in UPPER_CASE.

Navigating the File System

In order to tell your Mac where a file is, you’ll need to be able to navigate the file system. To do so, we can use the change directory (cd) and list files (ls) commands. In the code block below, each line that begins with a $ represents user input, and the subsequent line (if there is one) is output being printed to the Terminal.

$ ls 
example.txt example
$ cd example
$ ls
example2.txt
$ cd ..
$ ls
example.txt example

First, we list the files and directories in our current directory by running ls. We see that there is a file called example.txt and a directory called example. We then cd into the example directory, and run ls again. There, we find a second file called example2.txt.

We then cd back up one "level" in the file system by running cd .., which puts us back in the directory where we started. Finally, we confirm that we are, in fact, back where we started by running ls one last time.

We can also change to any directory we have the file path for and then return to the home directory, like so:

cd /Users/example_user/projects/my_cool_project 
cd

Key Unix Commands to Know

cd – Change directory

cd /Users/admin/example_directory

ls – List contents of a directory

ls /Users/admin/example_directory

cat – Read the contents of a file

cat /Users/admin/example_directory/example.txt

cp – Copy a file or directory

cp /example_directory/example.txt /second_example_directory/example.txt

mv – Move a file or directory (or rename it)

mv /example_directory/example.txt /example_directory/example-v2.txt

grep – Filter text (and -l list the matching results)

grep -l "these exact characters" example.txt

Piping output from one command to the next

One of the most powerful aspects of shell scripting is the ability for users to “pipe” output from one command to the next with the | character.

For example, list only files that contain “example” in the filename:

ls | grep -l example

Writing and running a simple shell script in the Terminal app on macOS

A shell script can be as simple as a list of commands like we looked at above to be carried out in sequence. You’ll want to tell the shell explicitly what interpreter should read the code with a standard first line called a “shebang.”

#!bin/bash 

cd
mkdir example_output && cd example_output
ls
echo "Hello World" >> example.txt
ls
cat example.txt

You can run the above example by pasting that text into a text file called example.sh. You’ll then need to navigate to the file’s location in the Terminal and run:

chmod +x example.sh      # only needs to be run the first time 
rm -rf example_output # get rid of any old examples if they exist
./example.sh

You should see the output:

example.txt 
Hello World!

TL;DR

First learning to use the Terminal app on macOS can be intimidating. But as we’ve shown above, it is pretty straightforward, and you will level up big time as a Mac user or admin when you begin to access resources and automate processes in this way.