Skip to content

Instantly share code, notes, and snippets.

@albertbori
Last active June 12, 2025 15:43
Show Gist options
  • Save albertbori/1798d88a93175b9da00b to your computer and use it in GitHub Desktop.
Save albertbori/1798d88a93175b9da00b to your computer and use it in GitHub Desktop.
Automatically disable Wifi when an Ethernet connection (cable) is plugged in on a Mac
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.asb.toggleairport</string>
<key>OnDemand</key>
<true/>
<key>ProgramArguments</key>
<array>
<string>/Library/Scripts/toggleAirport.sh</string>
</array>
<key>WatchPaths</key>
<array>
<string>/Library/Preferences/SystemConfiguration</string>
</array>
</dict>
</plist>

Overview

This is a bash script that will automatically turn your wifi off if you connect your computer to an ethernet connection and turn wifi back on when you unplug your ethernet cable/adapter. If you decide to turn wifi on for whatever reason, it will remember that choice. This was improvised from this mac hint to work with Yosemite, and without hard-coding the adapter names. It's supposed to support growl, but I didn't check that part. I did, however, add OSX notification center support. Feel free to fork and fix any issues you encounter.

Most the credit for these changes go to Dave Holland.

Requirements

  • Mac OSX 10+
  • Administrator privileges

Installation Instructions

  • Copy toggleAirport.sh to /Library/Scripts/
  • Run chmod 755 /Library/Scripts/toggleAirport.sh
  • Copy com.mine.toggleairport.plist to /Library/LaunchAgents/
  • Run chmod 600 /Library/LaunchAgents/com.mine.toggleairport.plist
  • Run sudo launchctl load /Library/LaunchAgents/com.mine.toggleairport.plist to start the watcher

Uninstall Instructions

  • Run sudo launchctl unload /Library/LaunchAgents/com.mine.toggleairport.plist to stop the watcher
  • Delete /Library/Scripts/toggleAirport.sh
  • Delete /Library/LaunchAgents/com.mine.toggleairport.plist
  • Delete /private/var/tmp/prev_eth_on
  • Delete /private/var/tmp/prev_air_on

Misc

To debug, just run: sudo /Library/Scripts/toggleAirport.sh and add echo's wherever you'd like

#!/bin/bash
function set_airport {
new_status=$1
if [ $new_status = "On" ]; then
/usr/sbin/networksetup -setairportpower $air_name on
touch /var/tmp/prev_air_on
else
/usr/sbin/networksetup -setairportpower $air_name off
if [ -f "/var/tmp/prev_air_on" ]; then
rm /var/tmp/prev_air_on
fi
fi
}
function growl {
# Checks whether Growl is installed
if [ -f "/usr/local/bin/growlnotify" ]; then
/usr/local/bin/growlnotify -m "$1" -a "AirPort Utility.app"
else
osascript -e "display notification \"$1\" with title \"Wifi Toggle\" sound name \"Hero\""
fi
}
# Set default values
prev_eth_status="Off"
prev_air_status="Off"
eth_status="Off"
# Grab the names of the adapters. We assume here that any ethernet connection name ends in "Ethernet"
eth_names=`networksetup -listnetworkserviceorder | sed -En 's|^\(Hardware Port: .*Ethernet, Device: (en.)\)$|\1|p'`
air_name=`networksetup -listnetworkserviceorder | sed -En 's/^\(Hardware Port: (Wi-Fi|AirPort), Device: (en.)\)$/\2/p'`
# Determine previous ethernet status
# If file prev_eth_on exists, ethernet was active last time we checked
if [ -f "/var/tmp/prev_eth_on" ]; then
prev_eth_status="On"
fi
# Determine same for AirPort status
# File is prev_air_on
if [ -f "/var/tmp/prev_air_on" ]; then
prev_air_status="On"
fi
# Check actual current ethernet status
for eth_name in ${eth_names}; do
if ([ "$eth_name" != "" ] && [ "`ifconfig $eth_name | grep "status: active"`" != "" ]); then
eth_status="On"
fi
done
# And actual current AirPort status
air_status=`/usr/sbin/networksetup -getairportpower $air_name | awk '{ print $4 }'`
# If any change has occured. Run external script (if it exists)
if [ "$prev_air_status" != "$air_status" ] || [ "$prev_eth_status" != "$eth_status" ]; then
if [ -f "./statusChanged.sh" ]; then
"./statusChanged.sh" "$eth_status" "$air_status" &
fi
fi
# Determine whether ethernet status changed
if [ "$prev_eth_status" != "$eth_status" ]; then
if [ "$eth_status" = "On" ]; then
set_airport "Off"
growl "Wired network detected. Turning AirPort off."
else
set_airport "On"
growl "No wired network detected. Turning AirPort on."
fi
# If ethernet did not change
else
# Check whether AirPort status changed
# If so it was done manually by user
if [ "$prev_air_status" != "$air_status" ]; then
set_airport $air_status
if [ "$air_status" = "On" ]; then
growl "AirPort manually turned on."
else
growl "AirPort manually turned off."
fi
fi
fi
# Update ethernet status
if [ "$eth_status" == "On" ]; then
touch /var/tmp/prev_eth_on
else
if [ -f "/var/tmp/prev_eth_on" ]; then
rm /var/tmp/prev_eth_on
fi
fi
exit 0
@keenonkites
Copy link

@adamshand Many thanks for your script, really helpful and straight forward.

The only issue I have with it is that it supports only one ethernet port. This is problematic for me as at home I'm connected to a dockingstation with an builtin ethernet port, in the office I'm connected to another brand dockingstation with a builtin ethernerport (other identifier, obviously) and when I'm on the run at customer side I have a normal USB to Ethernet Adaptor.

Optimally the script would support multiple Ethernet interfaces and toggle wifi off as soon as at least one of the cabled connections is connected.
I don't think this problem is relevant for wifi connections as you're normally running on the one that is built in on the computer and not attaching external ones. For wifi the actual behaviour fits perfectly.

Would be great if that could be implemented too.
Cheers Patrik

@adamshand
Copy link

@keenonkites glad the script has been useful! Unfortunately, I don't have a dock with two ethernet ports, so I can't test this.

@jamescamping
Copy link

@keenonkites I made a change to the script that seems to work based on some limited testing. Try it out and see if it behaves:
https://gist.github.com/jamescamping/f477809c1545c27ed60d20009b06a3a8

@adamshand
Copy link

I made a change to the script that seems to work based on some limited testing.

👍🏻

@keenonkites
Copy link

Thanks for the quick reaction.

It does not run on my end as It still bails out with 'Multiple ethernet interfaces match as I have e.g. in the office here multiple Display Ethernet and multiple LAN:

$ networksetup -listnetworkserviceorder | grep -e 'Display Ethernet' -e LAN
(1) Belkin USB-C LAN
(Hardware Port: Belkin USB-C LAN, Device: en8)
(3) Display Ethernet
(Hardware Port: Display Ethernet, Device: en9)
(6) Display Ethernet 2
(Hardware Port: Display Ethernet, Device: en10)
(7) Display Ethernet 3
(Hardware Port: Display Ethernet, Device: en11)
(11) USB 10/100/1G/2.5G LAN
(Hardware Port: USB 10/100/1G/2.5G LAN, Device: en6)

The script output is the following (I'm connecte to ethernet actually:
$ ./wifi-toggle.sh run
DEBUG: get_interface(): regex '(Wi-Fi|Airport)' -> interface 'en0'
DEBUG: Checking ethernet regexes: LAN Ethernet
DEBUG: Trying ethernet regex: 'LAN'
ERROR: Multiple ethernet interfaces match: LAN
DEBUG: No interface found for regex 'LAN'
DEBUG: Trying ethernet regex: 'Ethernet'
ERROR: Multiple ethernet interfaces match: Ethernet
DEBUG: No interface found for regex 'Ethernet'
DEBUG: No active ethernet interfaces found
DEBUG: ethernet status: 'inactive', wifi status: 'inactive'
DEBUG: enabling wifi

Actually I played around aswell with the script and came up with a solution that supports multiple matches with one REGEX and just checks if at least one interface is connected. The script is attached.
The only thing that actually isn't covered properly and should be covered the same way as in your original script is the case if the Wifi REGEX matches more than one interface.

  • then we should either bail out
  • or turn off all wifi interfaces

I've also added a quick command 'list' to see what interfaces matches the different REGEX to double check if all needed is covered.

My version can be found at https://gist.github.com/keenonkites/9dc158bd63c43f6ff294ed9dd34bea31

Have a look and take whatever snippets you want (if any) for backporting.

Cheers Patrik

@elements4me
Copy link

elements4me commented Jun 12, 2025

Original script didn't work for me initially. Had to change the REGEX for variable eth_names in toggleAirport.sh as my network is connected via usb-c adapter. After this it worked like expected. Thanks a lot!

eth_names="networksetup -listnetworkserviceorder | sed -En 's|^\(Hardware Port: USB 10/100/1000 LAN, Device: (en.)\)$|\1|p'"

@kMikaZu
Copy link

kMikaZu commented Jun 12, 2025

My version can be found at https://gist.github.com/keenonkites/9dc158bd63c43f6ff294ed9dd34bea31

The link is dead.

@keenonkites
Copy link

keenonkites commented Jun 12, 2025

Let's try it with this link again....
https://gist.github.com/keenonkites/9dc158bd63c43f6ff294ed9dd34bea31

(the link was written correct, but a click didn't function as I messed up name and URL)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment