Apple Shortcuts Logo

I Have Made Fire – Shortcut with Shell Script to Mount a NAS Share

I’m a huge fan of the well-known app Hazel from Noodlesoft. You’ve probably heard of it and may use it yourself, but just in case you haven’t I’ll briefly describe what it does and the problem it solves for me.

Hazel watches folders you specify and then takes action on the items in those folders according to rules you specify. Many people learned to use Hazel during the dawn of the paperless movement, because Hazel can recognize text patterns, set the name of the scanned document to match, and then file away scanned documents into folders according to those names. While Steve and I use Hazel in this way, I have another huge use case for this delightful tool.

I create a lot of data every week with the podcasts. The audio and image files for the NosillaCast and Chit Chat Across the Pond add up to around 4GB per week. You can imagine that if I didn’t pay attention, I’d soon be out of disk space. In the old days, I had to remember to go clean out these directories by hand, but with Hazel, I have it all automated. I still want to keep these files but they don’t need to live on my internal laptop drive. When a podcast episode ages past two weeks, my rules tell Hazel to sweep up after me and whisk all of these files over to my network-attached storage (NAS).

In order to perform this magic, I have a tiny AppleScript in my rules for each folder that tells the application Finder to mount the volume for the share on my NAS. I didn’t write this AppleScript; it was actually written for me many years ago by one of the lovely developers who works on Chronosync. The AppleScript simply tells the Finder to try to mount the server by its IP address, and if it can’t do it, throw an error to tell me that it failed.

tell application "Finder"
        mount volume "smb://" as user name "podfeet" with password "PASSWORD"     
    on error errorText number errorNum
        set errorMsg to "Synology Wake Up error: " & errorText & " (" & errorNum & ") "
        display alert errorMsg
    end try
end tell
delay 10

This process works flawlessly. Until one of two things happens. As soon as I leave my home network, I am bombarded with error messages because that script can’t find my NAS to mount the share. My only recourse is to open Hazel and pause every rule that is associated with moving files to my NAS. I have to then put in a reminder to un-pause those rules when I come back home.

The other problem is that our NAS is in our spare bedroom. Whenever we have friends or family spend the night, Steve shuts it down so the noise and lights don’t bother our house guests. Personally, I’d just leave it running and tell them to live with it, but Steve is a much better host than I am.

The main reason I’d tell them to live with it is that again I get bombarded with error messages because my script can’t mount the share on the NAS, and Hazel warns me about this catastrophe. Again with the pausing and un-pausing dance.

I was recently chatting with Paul Kim, the awesome developer of Hazel, about my problem, and he made a suggestion that made me slap my head that I didn’t think of it before. He asked me why I don’t include in the script a test to find out if the server is available before trying to mount the drive. This was so obvious and yet it never occurred to me.

I solved the problem using a combination of Apple Shortcuts and a shell script. But guess what? I’d never written a successful shell script or Shortcut before. I confess that because I want you to realize that you can probably figure this out too. Don’t think I’m some accomplished developer now who knows how to write scripts. I’m just someone who has gained confidence by trying and having small victories. Those small victories give me more confidence to try the next time.

Why Not AppleScript?

Script Options in Hazel
Script Options in Hazel

I started by looking at the existing AppleScript I’d embedded in Hazel and thought about whether I wanted to invest time learning more about AppleScript. It’s certainly a very viable scripting language on the Mac, but it’s not getting any love from Apple these days and I really don’t like sticking with things that most likely are on their way out of fashion. If I’m going to learn something new, I’d rather learn it in an enthusiastically supported environment.

In Hazel, there’s a dropdown to allow you to choose the scripting language option, and in addition to AppleScript, I discovered that you can run JavaScript, Automator workflows, shell scripts, and Shortcuts.

I’ve tried several times to learn to use Shortcuts and every single time, I gave up because I couldn’t get it to do my bidding. I really did want to find something this automation technology could do for me. It was time to try Shortcuts yet again.

Starting in Shortcuts

I launched the Shortcuts app on my Mac and typed “server” into the search window for available actions. I was delighted to find the “Connect to Servers” action. The delightful thing about Shortcuts (and Automator before it) is that you can simply drag and drop these actions into a workflow. I dragged the Connect to Servers action into the workflow and it helpfully suggested I type in the smb:// method to make the connection.

SMB is a network file sharing protocol, which you’ll often hear referred to as Samba which is the free and open source implementation of the original SMB. Samba runs on Linux, Solaris, macOS, and Windows. Just like you type https:// to get to a website, you type smb:// to get to a server on your network.

I pointed the Connect to Server action to the IP address and file share name of my Synology NAS and ran the shortcut and boom, the share mounted as a volume on my desktop. I really felt like this was going to be an easy task. All I had to do next was to wrap a couple of if/then/else statements around that action and I’d be golden.

What Conditions Need to be Checked?

I knew that the most crucial if-statement I needed was to only run this action if I was on the same network as the NAS. I did a search in Shortcuts for Network and found the action “Get Network Details”. Sounded like a good place to start, so I dragged it in before the connect to server action. Get Network Details can return the Network Name, so I was able to add an if statement comparing the network name to the name of my main WiFi network. From there, if they matched I could tell it to connect the server and mount the share.

Shortcut First Attempt Mount NAS
Shortcut First Attempt Mount NAS

I tested it while on my main WiFi network and it successfully mounted the server share. I switched to my guest WiFi network, and it skipped over the connect to server part and stopped silently with no annoying warnings about not being able to find it.

This was a great start, but there are three issues with this.

  1. I’d have to be on WiFi for this to work. When I’m streaming video for the live show or as a guest on other shows, I always disable WiFi because it makes for a more stable connection.
  2. While this workflow solves the first problem of checking to see if I’m on my home network, it doesn’t tell me that the server is alive on the network. It will fail if Steve puts the Synology to sleep.
  3. Finally, and surprisingly, if the server is already mounted, the Shortcut fails and pops up an alert telling me it failed.
Shortcut First Attempt Fails If Mounted
Shortcut First Attempt Fails If Mounted

So while Shortcuts is easy and quick, just like Automator before it I had to bring out heavier tools to create a workflow that could provide the granularity I required. It was time to use a shell script. I wasn’t going to abandon Shortcuts, but rather use a combination of the two tools.

Is the Server Alive on the Network?

Before I walk through how I figured out what to put in a shell script, let me quickly explain what a shell script actually is. You know how you can open the Terminal and type in a command? That command you’re typing is going into what’s called a shell. Shell scripts are just a bunch of Terminal shell commands piled together. For example, in Terminal you can type cd ~ where the ~ means your home directory. When I type cd ~ it takes me to /User/allison. To create a shell script for the same action, I could open Text Edit and type in cd ~, save the file as myScript.txt, and then run it as a shell script. I’m sure the real nerds are having fits to hear me explain it so simplistically, but I’ll say it again, a shell script is just a bunch of Terminal commands you run one after another.

I mentioned upfront that I’ve never actually written a shell script before, but luckily the Internet has written lots of them. It’s all about figuring out the right search terms. The first thing I wanted my fancy shell script to do was to find out if my NAS was alive on the same network as my Mac.

My NAS has a static IP address, which will be helpful in identifying if it’s alive on the network. In the terminal, you can ping an IP address to find out if there’s an active device at that IP. Just like pinging in a submarine to find potential enemies, when you ping an IP, you don’t actually find out what’s at that address, you just know something is there. Just like pinging in a submarine where you send sound out and see if it reflects back, pinging an IP address sends a packet of data at that address and waits to see if it echoes it back. Make sense?

I figured I could ping the NAS to see if it’s there, but the ping command by itself never stops. I only need one packet sent and echoed back to know that the server is alive at that address. I did some googling and found that adding -c 1 to the ping command would mean to count to 1 packet and then stop. Since my shell script is just going to be a pile of Terminal commands, I can test each one in my Terminal. While on the same network with the server, I typed into the Terminal ping -c 1, and sure enough, it sent one packet of data, it was echoed back and the command stopped.

Then I switched networks so that the server shouldn’t be found. The same command definitely failed to find the server, but it took forever. “Forever” was actually a couple of seconds, but why wait around if the server just isn’t there. It’s not like I’m trying to ping a server in Nepal, it should be on my internal network so it will either respond instantly or not at all.

I did some reading of the man page for ping (man is short for manual) and found the flag -W which lets you define the wait time in milliseconds. One millisecond is plenty of time on my home network for me to know if my server is alive.

Now with the command ping -c 1 -W 1 myServerIP I can instantly know whether the server is there. I tested it on and off the main network and it succeeded and failed instantly. I was ready to start writing my shell script.

I searched in Shortcuts actions for “script”, found the Run Shell Script action, and dragged it into my workflow.

I pasted the full ping command into the shell script and then ran the action. I thought that my if/then/else statements would have to rely on interpreting the success or failure messages returned by the ping command, but it was much simpler than that. I discovered that if the ping command succeeds, it returns true, and if it fails, it returns false.

I only had to write if ping -c 1 -W 1 "$ip"; then which means if the ping succeeds, then take the next action.

Sure it’s nerdier than my original “find out if it’s on the same WiFi network” Shortcut, but this test works whether I’m on WiFi or hard-wired Ethernet.

Is the Server Already Mounted?

Remember that my Shortcut failed if it tried to mount the server when it was already mounted, so now I had to figure out how to determine if the server is already mounted. If it isn’t, the script should mount it, but if it is, the script should just stop silently.

I have to get just a smidge nerdier here, but I promise it won’t hurt. I want to teach you two very easy concepts. The first is the command grep. Think of grep as a synonym for the word “search”. It’s a funny word but a simple concept.

The second term is called “pipe” but it’s a symbol, not a word. On a US keyboard, pipe is the vertical line above the return key. Piping means to hand off the result of one command to another command. In my shell script, I want to take the results of one search and hand it off to a second search. So I’m going to grep for a search term, and then I’ll pipe the results of that search into another grep to narrow the results. So it will be grep, pipe, grep. With me so far?

I discovered in my googling that the simple command mount in the Terminal will show you every Volume mounted on your Mac. It’s actually pretty interesting. You can see System volumes like Preboot and Update, you can see your Data Volume, services like Google Drive, and any local servers you have mounted. We can search the results of the mount command by handing off the results (piping) to our new friend grep. Put that in an if statement and we finally know whether the server is alive on the same network: mount | grep serverIP.

I won’t take the explanation of the shell script any further because I think you get the basic idea. I have figured out at the command line and thus in a shell script how to test whether the server is alive on the same network and then test to see if it’s already mounted. I told the script to echo back one of three messages depending on the results:

  • “IP is pining for the fjords” if it didn’t find the IP on the network
  • “Server is mounted already” if it found the IP but the server was already mounted
  • “Server is unmounted” if it found the IP but the server was unmounted.

That bit about the IP pining for the fjords was a funny return message someone posted in a forum and I decided to keep it, because checking to see if the echoed message said anything about fjords was easy and just darn fun.

My Finished Shell Script as described in the 2000 words before now!
My Finished Shell Script

Back to Shortcuts

At this point, I’m relatively certain that I could have finished the entire automation just using a shell script, but I was determined to finally get a Shortcut to do something useful for me so embedded the shell script into Shortcuts and used the logic in Shortcuts to complete the job.

My shell script will now tell me one of those three answers, so now I need to feed the answers into a variable so that the Shortcut will know whether or not to try to mount the server share.

In Shortcuts, it’s pretty easy to get a variable out of a previous action. But for some reason, you can’t do it directly that I’ve found. I wanted to first capture the output message from my shell script so I could test to see if it included the word “fjord”. Oddly, it’s a two-step process. First, you have the output flow into a Text action, and then from the Text action, you can capture it as a variable. Dragging a Text action below the Shell script allowed me to “Get text from” and then it auto-filled Shell Script Result. Now that it was considered text, I could set a variable name to the text I’d just acquired. Seems silly since the echoed information was already text, but that’s just how it works.

Once I cracked the code on creating variables from text, I was ready to run some if/then/else actions. If that text variable contains the word “fjords” then we know the server is unavailable. I could then put in a conditional that says “if the variable does NOT contain the word ‘fjords’, then I know it IS on the network, so lets keep going.” To create these conditionals, Shortcuts actions has one called “if” which you can drag in, and then it plops the “then” and “else” actions in for you.

After determining that it IS on the network (since the variable doesn’t contain “fjords”) I can run another “if/then/else” set of conditionals to check to see if the share is mounted or not. If it’s not mounted, only then should the Shortcut connect to the server.

And it all worked! I felt like I had made 🔥!

Would this be Helpful to You?

I’d been talking to Steven Goetz in Telegram while I was working on this, and he started working on his own version along with me. He wanted to have something similar. It was super fun to pass ideas back and forth while we were both learning.

When I got my version working, I wanted to give it to him so he didn’t have to build it himself. If I was going to share the Shortcut, it made sense to put in comments explaining what it was doing and how. I also thought it would be more useful if I assigned some variables for the IP address and the share name. That way, Steven could simply replace the placeholder for the IP address with the one for his NAS, and the share he wants to mount and not have to do a search and replace for every instance.

Once I’d done that for Steven, I realized I could share my Shortcut with you. Luckily Apple has a built-in share option that creates an iCloud link so it’s easy to share the love. If you’d like to download my little Shortcut and use it yourself, enjoy: Mount Server Share on Local Network. As with anything you download from the Internet, please open it and read what it does and make sure you understand it before running it with reckless abandon!

Bottom Line

I am really pleased with my Shortcut and my shell script. I solved a real problem by automating it away, and I learned a lot! I will never have to fuss with Hazel again when I’m away from home, and now I won’t resent our sleepover company when they come to stay. I have to thank Paul Kim for giving me the (obvious) idea, and Steven Goetz for helping me think through all of this.

I’m sure there are more efficient and elegant solutions out there, but it doesn’t make me any less proud of what I’ve accomplished. The best part is that when I pointed Hazel at my fancy new Shortcut, it actually WORKED!

Next up – I’m going to add my Shortcut to my Stream Deck so I can mount my share with a push of a button any time I need it.

Leave a Reply

Your email address will not be published.

Scroll to top