How do I make a Mac Terminal pop-up/alert? Applescript? - macos

I want to be able to have my program display an alert, notice, whatever that displays my custom text. How is this done? Also, is it possible to make one with several buttons that sets a variable?
Similar to batch's:
echo msgbox""<a.vbs&a.vbs

Use osascript. For example:
osascript -e 'tell app "Finder" to display dialog "Hello World"'
Replacing “Finder” with whatever app you desire. Note if that app is backgrounded, the dialog will appear in the background too. To always show in the foreground, use “System Events” as the app:
osascript -e 'tell app "System Events" to display dialog "Hello World"'
Read more on Mac OS X Hints.

Use this command to trigger the notification center notification from the terminal.
osascript -e 'display notification "Lorem ipsum dolor sit amet" with title "Title"'

If you're using any Mac OS X version which has Notification Center, you can use the terminal-notifier gem. First install it (you may need sudo):
gem install terminal-notifier
and then simply:
terminal-notifier -message "Hello, this is my message" -title "Message Title"
See also this OS X Daily post.

Adding subtitle, title and a sound to the notification:
With AppleScript:
display notification "Notification text" with title "Notification Title" subtitle "Notification sub-title" sound name "Submarine"
With terminal/bash and osascript:
osascript -e 'display notification "Notification text" with title "Notification Title" subtitle "Notification sub-title" sound name "Submarine"'
An alert can be displayed instead of a notification
Does not take the sub-heading nor the sound tough.
With AppleScript:
display alert "Alert title" message "Your message text line here."
With terminal/bash and osascript:
osascript -e 'display alert "Alert title" message "Your message text line here."'
Add a line in bash for playing the sound after the alert line:
afplay /System/Library/Sounds/Hero.aiff
Add same line in AppleScript, letting shell script do the work:
do shell script ("afplay /System/Library/Sounds/Hero.aiff")
List of macOS built in sounds to choose from here.
Paraphrased from a handy article on terminal and applescript notifications.

This would restore focus to the previous application and exit the script if the answer was empty.
a=$(osascript -e 'try
tell app "SystemUIServer"
set answer to text returned of (display dialog "" default answer "")
end
end
activate app (path to frontmost application as text)
answer' | tr '\r' ' ')
[[ -z "$a" ]] && exit
If you told System Events to display the dialog, there would be a small delay if it wasn't running before.
For documentation about display dialog, open the dictionary of Standard Additions in AppleScript Editor or see the AppleScript Language Guide.

And my 15 cent. A one liner for the mac terminal etc just set the MIN= to whatever and a message
MIN=15 && for i in $(seq $(($MIN*60)) -1 1); do echo "$i, "; sleep 1; done; echo -e "\n\nMac Finder should show a popup" afplay /System/Library/Sounds/Funk.aiff; osascript -e 'tell app "Finder" to display dialog "Look away. Rest your eyes"'
A bonus example for inspiration to combine more commands; this will put a mac put to standby sleep upon the message too :) the sudo login is needed then, a multiplication as the 60*2 for two hours goes aswell
sudo su
clear; echo "\n\nPreparing for a sleep when timers done \n"; MIN=60*2 && for i in $(seq $(($MIN*60)) -1 1); do printf "\r%02d:%02d:%02d" $((i/3600)) $(( (i/60)%60)) $((i%60)); sleep 1; done; echo "\n\n Time to sleep zzZZ"; afplay /System/Library/Sounds/Funk.aiff; osascript -e 'tell app "Finder" to display dialog "Time to sleep zzZZ"'; shutdown -h +1 -s

Simple Notification
osascript -e 'display notification "hello world!"'
Notification with title
osascript -e 'display notification "hello world!" with title "This is the title"'
Notify and make sound
osascript -e 'display notification "hello world!" with title "Greeting" sound name "Submarine"'
Notification with variables
osascript -e 'display notification "'"$TR_TORRENT_NAME has finished downloading!"'" with title " ✔ Transmission-daemon"'
credits: https://code-maven.com/display-notification-from-the-mac-command-line

I made a script to solve this which is here.
Installation:
brew install akashaggarwal7/tools/tsay
Usage:
sleep 5; tsay
Feel free to contribute!

Related

mac unix: Get name of terminal I am using through commands

I am looking for a terminal command that will open a new tab in the current terminal that I am using. For example, I run the command in iTerm 2 and a new tab opens in iTerm2 because that is the terminal that i am using.
I know how to open a tab by naming a static application like so:
osascript -e 'tell application "iTerm" to activate' \
-e 'tell application "System Events" to tell process "iTerm" to keystroke "t" using command down'
But of course this still opens iTerm if I am doing something like calling the command from mac's Terminal. I would love to do something like below, but I am unsure how to get the name of the terminal I am using.
currentTerminal = getCurrentTerminalApplicationName()
osascript -e 'tell application "&{currentTerminal}" to activate' \
-e 'tell application "System Events" to tell process "&{currentTerminal}" to keystroke "t" using command down'
I am also open to other ideas.
While inside macOS terminal:
env | grep TERM
TERM_PROGRAM=Apple_Terminal
While inside iTerm2:
env | grep TERM
TERM_PROGRAM=iTerm.app
UPDATE
You can always do something like this:
#!/bin/bash
if [ "$TERM_PROGRAM" == "iTerm.app" ]; then
echo "iTerm2"
cat <<EOF >/tmp/file.py
import iterm2
async def main(connection):
app = await iterm2.async_get_app(connection)
window = app.current_terminal_window
if window is not None:
await window.async_create_tab()
else:
print("No current window")
iterm2.run_until_complete(main)
EOF
$HOME/Library/Application\ Support/iTerm2/iterm2env-3.10/versions/3.10.4/bin/python /tmp/file.py
else
echo "not iTerm2"
fi
This code will open new tab inside iTerm2 - otherwise, it will do nothing.

How can I detect a button press reported by osascript in a calling shell?

I'm currently working on a script to notify a user when their password will expire. The prompt appears, but no matter what button I press, it results to the same outcome, "Change Later was chosen". Any ideas?
#!/bin/bash
button=$(osascript -e 'tell application "System Events" to display dialog "Change password now or later?" buttons {"Change Later", "Change Now"} default button 1 with title "Password Update Required" with icon caution')
if [[ $button = "Change Now" ]]; then
open /System/Library/PreferencePanes/Accounts.prefPane
echo "Opening Preferences"
else
echo "Change Later was chosen"
exit 0
fi
osascript doesn't simply output the name of the button you press; it outputs a more "descriptive" string, prefixed with button returned:. You need to account for that in your check:
if [[ $button = "button returned:Change Now" ]]
Also worth considering is that you are free to perform the check that determines which button was pressed in the AppleScript portion of the code as well, which in some ways makes more sense, as you can open System Preferences with it too:
#!/usr/bin/env bash
osascript << OSA 2>/dev/null && exit 0 || echo "Change Later was chosen"
display dialog "Change password now or later?" buttons ¬
{"Change Later", "Change Now"} default button 1 ¬
with title "Password Update Required" with icon caution
if the button returned of the result ¬
is "Change Later" then error
tell application id "com.apple.SystemPreferences"
reveal pane id "com.apple.preferences.users"
repeat until the id of the current pane is ¬
"com.apple.preferences.users"
delay 0.5
end repeat
activate
end tell
OSA
Here, rather than saving the outcome of the script to a variable, the exit status of osascript reflects the user's choice: "Change Later" terminates osascript with an error, thus returning an exit status of 1; "Change Now" allows the script to progress onward and opens System Preferences to the Users & Groups pane, before returning an exit status of 0.

osx installation script - detect if firefox is running and restart prompt

I am creating a command line tool for my application.
It uses pkgbuild and productbuild to create the package. Its a launchdaemon binary.
I have preinstall and postinstall scripts.
After installation, may be in postinstall script, I need to detect if Firefox is running, then a prompt to the user that (s)he need to restart Firefox.
Is it possible to do that? How?
some excerpt from the script, its part of the postinstall script.
.........
## Check if Firefox is running in the background with no tab/window open.
function restart_empty_firefox (){
echo "Restarting firefox if no tab is opened. "
firefoxRunning=$(osascript \
-e 'tell application "System Events" to set fireFoxIsRunning to ((count of (name of every process where name is "Firefox")) > 0)' \
-e 'if fireFoxIsRunning then' \
-e 'set targetApp to "Firefox"' \
-e 'tell application targetApp to count (every window whose (closeable is true))' \
-e 'else' \
-e 'return 0' \
-e 'end if')
if [ $firefoxRunning -eq 0 ]; then
echo 'Firefox is in the background with no window and so quitting ...'
osascript -e 'quit app "Firefox"'
else
##### show a dialog to the user to restart Firefox
fi
}
firefox_update # not shown here
restart_empty_firefox
.............
You can use the process status (ps) tool:
ps aux | grep '[F]irefox.app' | awk '/firefox$/ {print $2}'
Result:
82480
This tells us that Firefox.app is indeed running (process 82480).
EDIT: Since you seem to be leaning in the direction of using an osascript here's an example which asks the user to relaunch Firefox (putting full control in their hands):
#!/bin/bash
osascript <<'END'
set theApp to "Firefox"
set theIcon to "Applications:Firefox.app:Contents:Resources:firefox.icns"
tell application "System Events"
if exists process theApp then
display dialog "Warning: Mozilla " & theApp & " should be closed." buttons {"Continue"} with icon file theIcon default button 1
if the button returned of the result is "Continue" then
end if
end if
display notification "Installation complete" with title "Application Package" subtitle "Please relaunch " & theApp
delay 3
end tell
END
If your script has sufficient privileges then using quit would be recommended over blatantly killing off the process. Ultimately that's how it should be done, otherwise just ask the user to please quit and relaunch Firefox themselves — problem solved.

how to pass bash variables to AppleScript

#/bin/bash
corr="apple"
echo $corr
osascript -e 'tell application "Messages" to send "Did you mean "'"$corr"'" " to buddy "A"'
Error:
51:57: syntax error: A identifier can’t go after this “"”. (-2740)
If I just pass
osascript -e 'tell application "Messages" to send "Did you mean $corr " to buddy "A"'
the message comes like "Did you mean $corr"
I have tried everything mentioned at Pass in variable from shell script to applescript
There is a very good explanation with decent examples at the very end of here.
Based on that, I was able to make this work (using TextEdit, not Messages):
#!/bin/sh
rightNow=$(date +"%m_%d%B%Y")
osascript -e 'on run {rightNow}' -e 'tell application "TextEdit" to make new document with properties{name: "Date003.txt", text:rightNow}' -e 'end run' $rightNow
I also found that I had to be VERY careful about the single and double quotes. For some reason, my keyboard kept replacing the plain quotes with curled quotes. Annoying.

Why does a bash script continue running even though a dialog box is displayed on the screen waiting for an input from the user?

I have a bash script I'm using on Mac OS X (X.5 thru X.8) machines. In it is a dialog situation asking to continue the script by pressing "OK" or letting the script snooze by pressing "snooze". That part is working.
However, I was testing the script and wasn't able to press either button immediately and after a minute or two (i didn't time it), the script continued with the rest of process, letting the dialog stay on the screen.
I was under the impression that the script had to wait for user input?
Part of the script in question:
osascript -e 'tell app "Finder" to activate'
return=osascript -e 'tell app "Finder" to display dialog "Text goes here. Please select OK or Snooze" buttons {"OK", "Snooze"} default button 1 with title "Text Here" with icon caution'
############ BEGIN LOOP HERE ##############
while [ "$return" == "button returned:Snooze" ]
do
Runs every 4 hours
sleep 14400
osascript -e 'tell app "Finder" to activate'
return=`osascript -e 'tell app "Finder" to display dialog "Text goes here. Please select OK or Snooze" buttons {"OK", "Snooze"} default button 1 with title "Text Here" with icon 2'`
done
###### END LOOP HERE
if [ "$return" == "button returned:OK" ]
then
run the installer script here
fi
Try putting the whole right side of the return statement in back quotes, this will execute the osascript and set "return" to the string returned by that program:
return=`osascript -e 'tell app "Finder" to display dialog "Text goes here. Please select OK or Snooze" buttons {"OK", "Snooze"} default button 1 with title "Text Here" with icon caution'`
Otherwise you're just setting return to the string on the right side of the '='.
To ignore the timeout error you can try this.
We needed a script that prompts the user to change their password should there be 14 days or less until it expires. If they ignore the prompt the script will terminate due to the exit 0. You can edit this behaviour as you see fit but the point is that if anything else is returned apart from my condition test "button returned:OK" then the script will skip over the stuff I don't want it to run
if [ $daysRemaining -lt $daysBeforeExpire ]
then
echo "$userName has $daysRemaining day(s) remaining to change their password"
echo "Informing User..."
return=`osascript -e "tell application \"System Events\" to display dialog \"You have $daysRemaining day(s) to change your password... Logout and change password now?\" buttons {\"Later\",\"OK\"}"`
if [[ "button returned:OK" = $return ]]
then
echo "Returned OK"
echo "Asking to log out."
osascript -e "tell application \"System Events\" to log out"
else
echo "Returned Later - Skipping user log out"
exit 0
fi
else
echo "$daysRemaining day(s) remaining to change password"
fi
So in your case, this should work
if [[ "button returned:OK" = $return ]]
then
run the installer script here
else
sleep 100 #sleep the script OR
exit 0 #end it
fi

Resources