AppleScript's tell statement unconditionaly opens firefox, ignoring enclosing if block - macos

I'm experiencing the following issue
the script
osascript <<EOF
if false is true
tell application "Firefox" to activate
end if
EOF
will open/activate Firefox unconditionally, ignoring the enclosing if block. Any other statement inside the if block is (correctly) ignored.
If the application to open is anything But firefox, the statement is correctly ignored.
I.E - the following statement is ignored correctly
tell application "calculator" to activate
The issue is not exhibited when running from Script Editor, only via osascript
Is Firefox exclusively handled somehow by AppleScript? How do I overcome this behavior?

Firefox does not support AppleScript in that it does not contain an AppleScript dictionary file, no e.g. Firefox.sdef in its Resources folders within its application bundle, and only supports some of the basic commands of the Standard Suite.
To keep Firefox from opening with the code shown in your OP, you'll need to tokenize (set as a variable) its name, as in the following example:
osascript <<EOF
if false is true
set appName to "Firefox"
tell application appName to activate
end if
EOF
Or:
osascript <<EOF
if false is true
set |Firefox| to "Firefox"
tell application |Firefox| to activate
end if
EOF

Related

osascript syntax error "Expected expression but found end of line. (-2741)"

I am writing a bash script that utilizes AppleScript that disables the microphone and camera, and then clicks the "Join now" button on the google meet webpage. The portion that disables the microphone and camera works perfectly, but I am running into issues with the part of the script that is meant to click the join button. Here is the script:
#!/bin/bash
osascript <<EOF
tell application "System Events"
delay 4
key code 14 using command down
delay 1
key code 2 using command down
delay 1
end tell
EOF
#the following is not working-
osascript <<EOF
tell application "brave"
tell active tab of window 1 to -
execute JavaScript "document.getElementById('Join now')[0].click();"
end tell
EOF
When the second part of the script tries to execute, I get this error:
62:63: syntax error: Expected expression but found end of line. (-2741)
How do I fix this error and get the script to execute properly (click the button)?
You do not have a proper line continuation character after to:
tell active tab of window 1 to -
Use: ¬, e.g.:
tell active tab of window 1 to ¬
The line continuation character can be created by typing optionL in Script Editor.
If it still throws an error, then put it all on one line, e.g.:
tell active tab of window 1 to execute JavaScript "document.getElementById('Join now')[0].click();"

Hide terminal window using applescript

The purpose of the current snippet is to run a script in a new terminal window and instantly hide it. The code below initially seems to work fine but as a result, if the window is manipulated using its visible property it simply disappears and doesn't seem to be executing. Right clicking on the Terminal app within the Dock displays like there is no terminal window at all.
tell application "Terminal"
-- New Terminal Window
set newTab to do script "caffeinate -u -t 900"
set caffeinateWindow to id of front window
tell window id caffeinateWindow
set index to 1
set visible to false
end tell
end tell
instead of telling the terminal use applesripts builtin possibilities:
do shell script "caffeinate -u -t 900"
if you ever want to pass parameters then do it like this:
set param to "900"
do shell script "caffeinate -u -t " & param
Note if a parameter might contain spaces you need to escape/quote it like this:
set param to "900"
do shell script "caffeinate -u -t " & quoted form of param
if you still need to hide a window do it like so:
tell application "System events"
try
set visible of application process "Terminal" to false
end try
end

Switching between two Mac terminal windows

I have an interactive bash script running in a Mac OSX bash Terminal window. I would like, from within that script, to
open a second Terminal window, print in it the content of a variable from the script in the first window,
keep that second window open somewhere on the screen while I continue interacting with the first window, and finally
have the second window closed when I do not need it anymore.
Since I am on Mac OSX, I am thinking of using osascript to run Applescript commands opening the second window, pasting the variable content in it and returning control to the first window, but I cannot make it work.
#!/bin/bash
var2print="I want this to print in the text window"
osascript -e '
tell application "Terminal"
tell window 1 # this just renames the first window
set custom title to "Main window"
end tell
do script # this opens a new window
tell window 1
set custom title to "Text window"
set selected to true # my first idea to put focus on this window
activate # my second idea to put focus on this window
end tell
end tell
'
printf "%s\n" "$var2print" # prints in main window, despite all efforts
read -sn 1 -p "Press any key to continue..."
Surprisingly to me, the very last command 'read' also takes place in the main window, but the focus is on the text window and I have to manually select the main window to press a key and end the script.
I have considered letting go of AppleScript and using the gnu-screen command instead, but it seems like overkill for my purpose to simply have some info displayed for a while.
Any help to better understand what's going on and to find a practical solution to switch between terminal windows would be greatly appreciated. W.
You can toggle two windows in Terminal.app with AppleScript this way
tell application "Terminal"
set index of window 2 to 1
end tell
window 1 is always the frontmost window
How about using a dialog box to display your message and go away automagically after a few seconds like this:
#!/bin/bash
bashvar="ZippedyDooDah"
osascript >/dev/null 2>&1 <<EOF
tell application "System Events" to display alert "$bashvar" buttons {"OK"} as warning default button "OK" giving up after 5
EOF
You can do it like this:
osascript -e 'tell app "Terminal" to do script "echo hello"'
Or, you can set a bash variable like this and send that for display:
MSG="FreddyFrog"
osascript<<EOF
tell app "Terminal"
do script "echo $MSG"
end tell
EOF
If you want to send it more than one message, you could make it tell you its tty as the command you pass, then you will have that in a file and you can send it further messages...
osascript -e 'tell app "Terminal" to do script "tty > tty.txt"'
If you now look in the file tty.txt you will see the device special file of the terminal window you created, some thing like /dev/ttys002, then you can do this from your original window
echo "Some stuff" > /dev/ttys002
echo "More stuff" > /dev/ttys002
or, more succinctly
echo hello > $(cat tty.txt)

OSX script to open a new iTerm window and run a command based on a variable

I am trying to use the iTerm example shown here in answer to another query.
Basically I have a list of about 20 text files representing reports from different servers. I want to read each file name in the directory they live in and from that build a shell command that exists in a commands directory, then open a new iTerm window and then execute that shell script that I built.
I don't want to run them all in one window one after the other, I want them each to execute in their own window to speed up the processing.
Here is what I have, I can build the shell script name and store in foo quite happily and it seems I can open the new iTerm window OK too, but it is getting it to accept $foo as the command to be run I am having trouble with.
#!/bin/sh
FILES=/Volumes/reporter/uplod/lists/*
# eg each filename is of the type <path>/X07QXL29.txt
for f in $FILES
do
foo="del"
foo+=${f:32:1}
foo+=${f:36:2}
foo+=".sh"
# foo is now for example del729.sh using the above comment as the filename
# foo is the command I will want to run in its own new window
osascript <<END
tell application "iTerm"
tell the first terminal
tell myterm
launch session "Default Session"
tell the last session
write text "$foo"
write text "\n"
end tell
end tell
end tell
END
done
The error I am getting is:deltrash.sh: line 22: syntax error: unexpected end of file
Can anyone please give me a pointer?
Looking at iTerm applescript examples, something like that should work. Basically you have to set myterm variable to new terminal instance. Also be sure to put END marker at the beginning of line. It is not detected in your script, hence unexpected end of file error.
#!/bin/sh
FILES=/Volumes/reporter/uplod/lists/*
# eg each filename is of the type <path>/X07QXL29.txt
for f in $FILES
do
foo="del"
foo+=${f:32:1}
foo+=${f:36:2}
foo+=".sh"
# foo is now for example del729.sh using the above comment as the filename
# foo is the command I will want to run in its own new window
osascript <<END
tell application "iTerm"
set myterm to (make new terminal)
tell myterm
launch session "Default Session"
tell the last session
write text "$foo"
write text "\n"
end tell
end tell
end tell
END
done

Programmatically launch Terminal.app with a specified command (and custom colors)

I can launch an xterm from the command line (or a program, via a system call) like so:
/usr/X11/bin/xterm -fg SkyBlue -bg black -e myscript
That will launch an xterm with blue text and a black background, and run an arbitrary script inside it.
My question: How do I do the equivalent with Terminal.app?
You can open an app by bundle id too, and give other parameters.
If there's an executable script test.sh in the current directory, the following command will open and run it in Terminal.app
open -b com.apple.terminal test.sh
The only down side that I can find is that Terminal doesn't appear to inherit your current environment, so you'll have to arrange another way to pass parameters through to the script that you want to run. I guess building the script on the fly to embed the parameters would be one approach (taking into account the security implications of course...)
Assuming you already have the colors you want in one of your Terminal profiles, here's what I came up with (with some help from Juha's answer and from this Serverfault answer).
Update:
On reflection, I think this echo business is too complicated. It turns out you can use osascript to make an executable AppleScript file with a shebang line:
#!/usr/bin/osascript
on run argv
if length of argv is equal to 0
set command to ""
else
set command to item 1 of argv
end if
if length of argv is greater than 1
set profile to item 2 of argv
runWithProfile(command, profile)
else
runSimple(command)
end if
end run
on runSimple(command)
tell application "Terminal"
activate
set newTab to do script(command)
end tell
return newTab
end runSimple
on runWithProfile(command, profile)
set newTab to runSimple(command)
tell application "Terminal" to set current settings of newTab to (first settings set whose name is profile)
end runWithProfile
Save that as term.scpt, make it executable with chmod +x, and use it the same way as below, e.g. term.scpt "emacs -nw" "Red Sands".
Original answer:
Assuming we save the script below as term.sh...
#!/bin/sh
echo '
on run argv
if length of argv is equal to 0
set command to ""
else
set command to item 1 of argv
end if
if length of argv is greater than 1
set profile to item 2 of argv
runWithProfile(command, profile)
else
runSimple(command)
end if
end run
on runSimple(command)
tell application "Terminal"
activate
set newTab to do script(command)
end tell
return newTab
end runSimple
on runWithProfile(command, profile)
set newTab to runSimple(command)
tell application "Terminal" to set current settings of newTab to (first settings set whose name is profile)
end runWithProfile
' | osascript - "$#" > /dev/null
...it can be invoked as follows:
term.sh
opens a new terminal window, nothing special
term.sh COMMAND
opens a new terminal window, executing the specified command. Commands with arguments can be enclosed in quotes, e.g. term.sh "emacs -nw" to open a new terminal and run (non-windowed) emacs
term.sh COMMAND PROFILE
opens a new terminal window, executing the specified command, and sets it to the specified profile. Profiles with spaces in their names can be enclosed in quotes, e.g. term.sh "emacs -nw" "Red Sands" to open a new terminal and run (non-windowed) emacs with the Red Sands profile.
If you invoke it with a bad command name, it'll still open the window and set the profile, but you'll get bash's error message in the new window.
If you invoke it with a bad profile name, the window will still open and the command will still execute but the window will stick with the default profile and you'll get an error message (to stderr wherever you launched it) along the lines of
525:601: execution error: Terminal got an error: Can’t get settings set 1 whose name = "elvis". Invalid index. (-1719)
The invocation is slightly hacky, and could probably be improved if I took the time to learn getopt (e.g., something like term.sh -p profile -e command would be better and would, for instance, allow you to easily open a new terminal in the specified profile without invoking a command). And I also wouldn't be surprised if there are ways to screw it up with complex quoting. But it works for most purposes.
Almost all (every?) osx program can be launched from command line using:
appName.app/Contents/MacOS/command
For terminal the command is:
/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal
You can use the autocomplete (tab) or ls to find the correct filenames. ".app" is basically a folder.
To change the colors and run a script... I think you cannot do it with shell scripts as Terminal does not accept arguments ("Terminal myScript.sh" does not launch myScript). With iTerm this works.
Workaround is to use applescript (wrapped in a shell script):
#!/bin/sh
osascript -e '
tell application "Terminal"
activate
tell window 1
do script "sleep 5; exit"
set background color to {0, 11111, 11111}
set win_id to id
end tell
set w_ids to (id of every window)
repeat while w_ids contains win_id
delay 1
set w_ids to (id of every window)
end repeat
end tell'
Ok, now it should behave exactly the same as the xterm example. The drawback is the constant polling of the window ids (which is bad programming).
edit: A bit more elegant applescript would use the 'busy' property of Terminal. I will leave the original code as is works for a general program (not just terminal).
tell application "Terminal"
tell window 1
do script "sleep 2"
set background color to {0, 11111, 11111}
repeat while busy
delay 1
end repeat
close
end tell
end tell
Also for perfectly correct program, one should check that whether the terminal is running or not. It affects the number of windows opened. So, this should be run first (again a nasty looking hack, that I will edit later as I find a working solution).
tell application "System Events"
if (count (processes whose name is "Terminal")) is 0 then
tell application "Terminal"
tell window 1
close
end tell
end tell
end if
end tell
br,
Juha
You can also go into terminal GUI, completely configure the options to your heart's content, and export them to a ".terminal" file, and/or group the configurations into a Window Group and export that to a terminal file "myGroup.terminal". Then
open myGroup.terminal
will open the terminal(s) at once, with all your settings and startup commands as configured.
you can launch terminal with the following command, not sure how to specify colors:
open /Applications/Utilities/Terminal.app/
The answer from #david-moles above works but run the terminal and command in ~ rather the current working directory where term was launched. This variation adds a cd command.
#!/usr/bin/env bash
# based on answer by #david-moles in
# https://stackoverflow.com/questions/4404242/programmatically-launch-terminal-app-with-a-specified-command-and-custom-colors
echo "
on run argv
if length of argv is equal to 0
set command to \"\"
else
set command to item 1 of argv
end if
set command to \"cd '"$PWD"' ;\" & command
if length of argv is greater than 1
set profile to item 2 of argv
runWithProfile(command, profile)
else
runSimple(command)
end if
end run
on runSimple(command)
tell application \"Terminal\"
activate
set newTab to do script(command)
end tell
return newTab
end runSimple
on runWithProfile(command, profile)
set newTab to runSimple(command)
tell application \"Terminal\" to set current settings of newTab to (first settings set whose name is profile)
end runWithProfile
" | osascript - "$#" > /dev/null
There may be a way to set PWD this with applescript.
Note: When I use this, I sometimes two Terminal windows, one a shell running in ~ and a second which runs the cd command and command from argv[1]. Seems to happen if Terminal is not already running; perhaps it is opening old state (even tho I had no open terminals when I closed it).

Resources