3

Hoping some one can point out what I am doing wrong. After looking through several threads, plus lots of experimentation, it feels like something simple is wrong. The threads I read include How can I trigger a Notification Center notification from an AppleScript or shell script? and How to get a notification when my commands are done

This script is intended for minimally technical users to perform mounting and un-mounting shares. Right now it only supports SMB, but will handle NFS and other remote mounts later. We have the constraint that the user's system will be the base OS X installation, therefore we cannot install other tools or libraries.

The problem is popping a notification window when an event occurs, with text that includes a space in the argument passed to the function. If the argument is only alpha/numeric, it works fine.

As a starting point, I am using a piece of code from randomor on How to get a notification when my commands are done. The say command makes it much easier to tell when the script works, plus will make for nice voice prompts.

send_notify(){
cmd=$@
local $@ && say 'Completed!' && osascript -e "display notification \"Completed: $2\" with title \"$1\""
}

As long as there isn't whitespace in the argument string being passed from the calling function, both the say and the notification work. When there is white space in the argument string such as "BAR 3" or in a variable being passed, the send_notify() function throws an error.

When called without whitespace, send_notify() works

send_notify "FOO" "BAR2" <<< This works

This fails because of the whitespace

send_notify "FOO" "BAR 3"  <<< This fails

./sharemount.sh: line 138: local: `37': not a valid identifier

Interestingly, the say command also fails to execute.

Part of the problem is my lack of understanding what role “$@" plays in this command. If anyone has an explanation, it would be very welcome.

Below is one of several functions in the script tha call the send_notify() function.

Pre_Mount_Check() {
    Current_Share="$(df -t smbfs --output=source 2>/dev/null | sed '1d' | awk -F/ '{print tolower($NF)}')"
    Current_MountPoint="$(df -t smbfs --output=target 2>/dev/null | sed '1d')"
    logger -p Info "$DebugLog" "Sharemount:Pre_Mount_Check Checking to see if $Share_Path already exists"

    if [[ (-z "$Current_Share") && (-z "$Current_MountPoint") ]]; then 
        logger -p Info "$DebugLog" "Sharemount:Pre_Mount_Check $Share_Path on $Mount_Point is not mounted, we will try to mount it"
        return 0

    elif [[ ( "$Current_Share" = "$Share_Name") && ( "$Current_MountPoint" = *"$Mount_Point"*) ]]; then 
        logger -p Info "$DebugLog" "Sharemount:Pre_Mount_Check $Share_Path already mounted, nothing to do, exiting"
        echo "$Share_Path already mounted, nothing to do, exiting 1"
        exit 0

    elif
     [[ ( "$Current_Share" = "$Share_Name") ]]; then
        logger -p Warning "$DebugLog" "Sharemount:Pre_Mount_Check $Share_Path already mounted, on $Current_MountPoint, exiting"
        echo "$Share_Path already mounted, on $Current_MountPoint, exiting 2"
        send_notify "FOO" "BAR2" <<< This works
        exit 36

    elif [[ ( "$Current_MountPoint" = *"$Mount_Point"*) ]]; then
        logger -p Warning "$DebugLog" "Sharemount:Pre_Mount_Check $Share_Name is already mounted on $Mount_Point exiting"
        echo "$Share_Name is already mounted on $Mount_Point exiting 3"
        send_notify "FOO" "BAR 3"  <<< This fails
        exit 0

    fi
}

send_notify(){
cmd=$@
local $@ && say 'Completed!' && osascript -e "display notification \"Completed: $2\" with title \"$1\""
}
bmike
  • 235,889
Kevin
  • 117
  • In Bash, the $@ expands to the positional parameters. One way to visualize this is if you wanted all the elements in an array, $@ would provide them. That said, I don't see what positional parameters are being set based on the code provided. One way to check is to simply echo $cmd and see what you get (I have a feeling, nothing). That said, there seems to be multiple questions here - can you narrow it down to just one (i.e. the notify problem as described in your title)? – Allan Aug 03 '19 at 22:02
  • When I remove it from the command, what was working doesnt. That is why i questioned what it actually did. The line that is causing the problem is send_notify "FOO" "BAR 3" <<< This fails the line that works is send_notify "FOO" "BAR2" <<< This works

    The two parameters translate into $1 and $2 for the send_notify() function. If either of those contains a white space, the entire function fails.

    Hope that clarifies the problem

    – Kevin Aug 03 '19 at 22:08
  • I wrote a "notify" script in Apple Script. See if this can assist you. As for what's working and what doesn't, we need to break it down into basic "blocks." For this question, let's see if we can get notifications working (regardless of what's mounted). We'll just manually set some conditions to see if it works. Then we can tackle the actual mounting of the drives. – Allan Aug 03 '19 at 22:10
  • Sorry I wasnt clear, everything except this notification function is working. Right now it can echo a message, but, i want it to use the OS X notification center. – Kevin Aug 03 '19 at 22:13
  • 1
    I don't know the purpose of "local $@". I think the intent is to create variables in the local address space. variables cannot have a space in them. What are you trying to do with the local statement? Why is it even there? – historystamp Aug 03 '19 at 22:27
  • 1
    I believe in over-the-top debugging, so I ended up with: https://pastebin.com/raw/SjVkSnPg – historystamp Aug 03 '19 at 22:40
  • @historystamp You avoided the use of osascript... is that changing the space delimiting? It seems to me that space delimiting is causing the issue. The example I posted below has spaces and no issues. – Thomas Nelson Aug 03 '19 at 23:07
  • @KevinMason. What happens if you take the subroutine out of it and do... osascript -e "display notification "Completed: Foo" with title "Bar 1"" – Thomas Nelson Aug 03 '19 at 23:09
  • @Thomas Nelson. No, osascript is still thre. What I did was put all the variables in ${output} so that I could see what was passed to osascript. local "${@}" && say 'Completed!' && osascript -e "${output}" I wasn't paying attention to what osascript was doing. I was trying to see if it was invoked at all. – historystamp Aug 04 '19 at 00:10
  • @Thomas Nelson. lets be clear. the spaces cause a problem with the local statement: "local $@ && say 'Completed!' && osascript -e ... " – historystamp Aug 04 '19 at 00:14
  • What is the purpose of the local statement? – historystamp Aug 04 '19 at 00:15
  • @historystamp I guess my confusion is what is the point of the subroutine if it is not needed and doesn't work? It looks like it is only used twice (unless there is more code...) I agree that subroutines are an easy way to prevent repetitive code but this may be more work than it is worth. – Thomas Nelson Aug 04 '19 at 08:52
  • @ThomasNelson If I do the subroutine directly, it works fine. The only problem is passing n argument that contains a space. – Kevin Aug 04 '19 at 14:10
  • @historystamp I am only showing one of several functions in the compete script that will need to create a notification. Other parts deal with displaying current mounts, discovering the AD domain and then the DFS share for the user. So rather than have to put in over and over in each of the other functions, it is easer to use a function. – Kevin Aug 04 '19 at 14:10
  • 1
    You still haven't explained the need for the local command at the front of the call to osascript & what you expect the local statement to do. – historystamp Aug 04 '19 at 20:57
  • 1
    Again Kevin this seems like a space delimiting issue. I dropped the 'cmd=$@' and the 'local $@ && ' from the code and it works. $1 and $2 work without any parsing. See https://www.tldp.org/LDP/abs/html/localvar.html for more info on passing variables. – Thomas Nelson Aug 05 '19 at 05:23
  • @ThomasNelson, thank you, that was it. Not sure how I managed to get myself spun into that corner. – Kevin Aug 05 '19 at 11:50
  • @historystamp Looking through my changes, I added the local in an attempt to pass the arguments and then never took it out as troubleshooting went on. . – Kevin Aug 05 '19 at 11:52
  • From some reason, I continue to program in bash scripts when a Python script would be easier. Bash scripts require a detailed knowledge on the handling of special characters like blank ," " , newline, "\n". – historystamp Aug 05 '19 at 19:08
  • @ThomasNelson For me, i can be sure all the libraries are there, not always the case on a production server. In a way, it is the same as mastering VI, it is obscure, but is ubiquitous.

    How do i mark your comment as a correct answer so you get credit?

    – Kevin Aug 06 '19 at 01:11

2 Answers2

2

Displaying Notifications Notification Center offers another opportunity for providing feedback during script execution. Use the Standard Additions scripting addition’s display notification command to show notifications, such as status updates as files are processed.

To show a notification, provide the display notification command with a string to display. Optionally, provide values for the with title, subtitle, and sound name parameters to provide additional information and an audible alert when the notification appears, as shown in Listing 24-1 and Listing 24-2.

APPLESCRIPT

Open in Script Editor

Listing 24-1AppleScript: Displaying a notification

display notification "All graphics have been converted." with title "My Graphic Processing Script" subtitle "Processing is complete." sound name "Frog"

JAVASCRIPT

Open in Script Editor

Listing 24-2JavaScript: Displaying a notification

var app = Application.currentApplication()

app.includeStandardAdditions = true

app.displayNotification("All graphics have been converted.", {
    withTitle: "My Graphic Processing Script",
    subtitle: "Processing is complete.",
    soundName: "Frog"
})

NOTE

After using a script to display a notification, the script or Script Editor (if the script is run from within Script Editor) is added to the list of notifying apps in System Preferences > Notifications. There, you can configure options, such as whether to display notifications as alerts or banners.

Clicking the Show button in an alert-style notification opens the app that displayed the notification. For a script app, the action of opening the app again triggers the run handler of the script, potentially causing the script to begin processing a second time. Keep this in mind, and add code to your script to handle this scenario, if appropriate.

From: https://developer.apple.com/library/archive/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/DisplayNotifications.html

2

As Thomas Nelson pointed out, I had made this way too complex. Dropping the

cmd=$@
local $@ && 

sequence solved the problem.

Here is the finished function

    #######################
    ##### Send_Notify #####
    #######################

    # Call this and supply the text you want to have spoken ($1) and the notification message ($2)
    # ie: Send_Notify "This is my voice" "This is the message"
    Send_notify(){
    title="FOOScript"
    say "$1" && osascript -e "display notification \"$2\" with title \"$title\""
}
Kevin
  • 117