Scripting macOS, part 6: Turn it off and on again

This series is an excerpt from the first chapter of my upcoming book “Scripting macOS” which will teach you to use and create shell scripts on macOS.

I will publish one part every week. Enjoy!

Turn it off an on again

A common strategy to solve problems with computers is ‘turning it off and on again.’ For example, when you have Wi-Fi connectivity problems, one of the first things you should try it to turn the Wi-Fi off, wait a few seconds, and then turn it on again.

Let’s write a script to do that.

Create the ‘frame’

When you start out writing a script, you will usually have only a vague idea of what needs to be done, and even less an idea of how to actually do it. In this case is helps to write out the steps that your script should perform:

  • turn off Wi-Fi
  • wait a few seconds
  • turn on Wi-Fi

With this list we have broken down the problem into smaller, more manageable steps, which we can each solve on their own.

I usually take this list of steps and build a script ‘frame’ from them:

#!/bin/zsh

# Reset Wi-Fi
# by turning it off and on again


# turn off Wi-Fi

# wait for a few seconds

# turn on Wi-Fi

We just copied our list of steps into the text file for our script and made them comments by adding the # character at the beginning of the line. We also added the shebang in the first line and two more comment lines at the beginning, which name the script and have short description on what it is supposed to do.

Since the script in this form only consists of the shebang and comments, it does nothing. But it provides a frame to fill in. Now we can tackle these steps one at a time.

Control Wi-Fi

When you want to control network related settings on macOS, the networksetup command is the first place you should look. The networksetup command allows you to configure the settings in the ‘Network’ pane in ‘System Preferences’— and a few more. The networksetup command has dozens of options. You can get a list and descriptions by running networksetup -help or in the networksetup man page.

To turn off Wi-Fi, you can use this option:

> networksetup -setairportpower <hwport> off

The value you need to use for <hwport> depends on what kind of Mac you are working on. For MacBooks, it will be en0 (unless you have a very old MacBook with a built-in ethernet port). For Macs with a single built-in ethernet port, it will be en1. For Macs with two built-in ethernet ports it will be en2.

You can also use the networksetup command to list all available hardware ports and their names:

> networksetup -listallhardwareports

Hardware Port: Wi-Fi
Device: en0
Ethernet Address: 12:34:56:78:9A:BC

Look for the Hardware Port named Wi-Fi. The value shown next to Device is the one you have to use. So, for me, on a MacBook, I will use:

> networksetup -setairportpower en0 off

We will use en0 in our sample script going forward. If your Wi-Fi port is different, remember to change it in your script going forward

Note: Apple used to brand Wi-Fi as ‘Airport’ and this naming still lingers in some parts of macOS. Changing networksetup’s options to match the new branding would break all existing scripts.

When you replace the off with on it will turn the Wi-Fi back on:

> networksetup -setairportpower en0 on

We have solved the first and third step for our script and tested them in the interactive shell. Now, we can fill them into our script frame:

#!/bin/zsh

# Reset Wi-Fi
# by turning it off and on again


# turn off Wi-Fi
networksetup -setairportpower en0 off 

# wait for a few seconds

# turn on Wi-Fi
networksetup -setairportpower en0 on

You can now save the script as reset_wifi.sh, set its executable bit and run it:

> chmod +x reset_wifi.sh
> ./reset_wifi.sh

This should already work. You should see the Wi-Fi icon in the dock switch to the animation indicating that it is re-connecting with your network.

Taking a break

We still want the script to ‘take a break’ and wait for a few seconds between the turning off and turning back on commands. This will allow other parts of system to ‘settle’ and react to the change.

In the shell you can use the sleep command to achieve this. It takes a single argument, the time in seconds it should pause before continuing:

> sleep 5

When you enter this command in the interactive shell, you should notice that it takes 5 seconds for the next prompt to appear. The sleep command is delaying progress for the given time.

When you watch the CPU load in Activity Monitor while you run the sleep command, you will not see a spike in load. The sleep command merely waits, letting other processes and the system do their thing.

Let us insert a ten second break into our script between the commands to turn Wi-Fi off and on:

#!/bin/zsh

# Reset Wi-Fi
# by turning it off and on again

# turn off Wi-Fi
networksetup -setairportpower en0 off 

# wait for ten seconds
sleep 10

# turn on Wi-Fi
networksetup -setairportpower en0 on

Now, when you run the script. You can see that Wi-Fi icon in the menu bar should switch to ‘disabled’ and then return to the ‘searching’ animation and eventually reconnect after ten seconds.

Feedback

While you are running this script, there is no feedback in the Terminal though. It just takes a disconcerting time for the prompt to return. We can add some output to let the user of the script know what is happening:

#!/bin/zsh

# Reset Wi-Fi
# by turning it off and on again


# turn off Wi-Fi
echo "Disabling Wi-Fi"
networksetup -setairportpower en0 off 

# wait for a ten seconds
echo "Waiting..."
sleep 10

# turn on Wi-Fi
networksetup -setairportpower en0 on
echo "Re-enabled Wi-Fi"

Now, the user will get some feedback in Terminal that lets them know what is going on.

>  ./reset_wifi.sh
Disabling Wi-Fi
Waiting...
Re-enabled Wi-Fi

Script Building Process

We formed an idea or a goal: ‘Turn Wi-Fi off and back on’

Then we described the steps necessary to achieve that goal:

  • turn off Wi-Fi
  • wait a few seconds
  • turn on Wi-Fi

We used these descriptive steps to create a frame or scaffolding script to ‘fill in’ with the proper commands.

Then we explored commands that would achieve these steps in the interactive terminal.

Once we determined the correct commands and options we placed them into our script ‘frame’ in the correct order.

As you add the commands, test whether the script shows the expected behavior.

Then we also added some output, to provide user feedback.

This is a really simple example script to illustrate this process. Nevertheless, we will re-visit these process steps with every script we build and you should follow this process (or a similar flow) when building your own scripts.

The process will not always be quite so clearly defined and you may have to iterate or repeat some of these tasks multiple times, before you find a combination of commands that do what you want. Less experienced scripters will naturally spend more time on ‘exploring commands.’ This is part of the normal learning process.

With larger, more complex scripts, each descriptive step may need to broken into even smaller sub-steps to manage the complexity. Again, experienced scripters will be able tackle more complex steps faster. Do not let that intimidate you when you are just beginning! Experience has to be built ‘the hard way’ by learning and doing.

In many situations you can learn from other people’s scripts that solve a similar problem. This is a well-proven learning strategy. I would still recommend to ‘explore’ the commands used in other people’s scripts before adding them to your scripts, as it will deepen your knowledge and experience with the commands. Sometimes, you may even be able to anticipate and avoid problems.

Next Post: Download and Install Firefox

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.