Get bash to stop running after x seconds - bash

So I have this Applescript:
on run{}
set myPath to path to me as text
set x to the length of myPath
set myPath to characters 13 thru x of myPath as string --Removes "Macintosh HD:" from the front of the file path
set myPath to my fileAdapt(myPath)
set lat to do shell script myPath & " -f \"{LAT}\"" --See comments below the script
set lon to do shell script myPath & " -f \"{LON}\""
end run
on fileAdapt(myPath)
set x to the length of myPath
set myPath1 to ""
repeat with i from 1 to x
if character i of myPath is ":" then
set myPath1 to myPath1 & "/"
else if character i of myPath is " " then
set myPath1 to myPath1 & "\\ "
else
set myPath1 to myPath1 & (character i of myPath)
end if
end repeat
set myPath1 to myPath1 & "Contents/Resources/LocateMe" as string --See comments below the script
return myPath1
end fileAdapt
where LocateMe is a bash script that can get a user's latitude and longitude, among other statistics, using the -f command.
The Issue
Now, on first run, the program asks for permission to get the user's location. If the user presses "OK," then all is good. But if the user presses "Cancel," we've got issues.
As I describe over on SuperUser regarding deleting applications from Location Services, LocateMe seems to continue running in the background until Location Services are turned back on. In the meantime, my Applescript just hangs until the bash script finishes loading, or until I force-quit the application (or Script Editor, whatever I'm running it in). Obviously, this is not a desirable behavior.
To make matters worse, once the application has asked for Location Services permission, it never asks again; the user has to manually go to System Preferences and tick the box themselves (or get a script to do it for him). What this means is that on a second run of this script, the user would have absolutely no way of knowing why the script is hanging.
My first attempt at dealing with this was to stuff LocateMe inside a try statement, but, as per my conclusion above, that wouldn't do anything; since LocateMe continues running until it gets access to the user's location, the Applescript never reaches the on error line.
My Question
I would like to know if there is a way to call LocateMe from within some sort of statement, be it an Applescript or a bash script or some other language that can be run from within an Applescript, that sets a time limit; if the time limit is not reached, LocateMe will be terminated, and the Applescript will display an error message to the user, explaining that location services must be turned on.

This is a possible duplicate of How to introduce timeout for shell scripting?
If you have timeout available, simply run timeout -k 10 Contents/Resources/LocateMe (where 10 is the number of seconds before timeout.
Otherwise either call that expect command directly, replacing $command with Contents/Resources/LocateMe, or copy that function into your .bashrc so that the function timeout is available in bash, and call that.
That expect example is defining a bash function - when you call functions with arguments, they get put into variables called $1, $2 etc. So for timeout 10 foo, $1 would be 10 and $2 would be foo. If you copy it 'as-is' into your .bashrc you can use it in the same way as the timeout command suggested above. Alternatively, just copy the expect line out of the function into your script, and replace all the variables with hard-coded values (time, command etc).

Related

Replace text in an applescript using an applescript

I have several hundred lengthy applescripts to edit where I need to find and replace the following code snippet in various places in each script.
tell application "Adobe Photoshop CC 2015.5"
set myLayer to current layer of current document
if last character of mySport is "s" then
set contents of text object of myLayer to mySport & ""
else
set contents of text object of myLayer to mySport & "'s"
end if
end tell
I want to replace it with
tell application "Adobe Photoshop CC 2015.5"
set myLayer to current layer of current document
set contents of text object of myLayer to mySport & "'s"
end tell
Is there a way to write an applescript to find and replace several lines?
code screen grab
The second problem is how do I deal with the apostrophe contained inside the quotes?
You can probably tell that I'm an artist and not a developer or scripter! I tried to get an answer a while back but unsuccessfully and the problem is now become critical.
Many thanks in anticipation of an answer.
The best would have been to set this subroutine as a separate script library and call it it in each of your scripts. Doing so, only one change would be enough. I advice you to do this way for next time.
I dig to find a way to make change in a script, but that's not that easy. Script Editor as very limited capability for scripting. the work around is to use the GUI scripting, which means that any changes made by Apple in future versions may no longer work.
The script bellow simulate your keyboard action to search & replace CurString to NewString :
set myScript to "Users:imac27:Desktop:Testscript.scpt" -- path to your script
set CurString to "Set B to 2"
set NewString to "Set X to 5"
tell application "Script Editor"
open myScript
activate myScript
delay 2
tell application "System Events"
keystroke "f" using {option down, command down} --mode search & replace
keystroke tab using {shift down} -- got to search area
keystroke CurString -- set the search target
keystroke tab -- goto replace area
keystroke NewString -- set replace value
-- click on menu "Replace all " which is the 7th item of "Search" menu item (=item 14th of menu "Edit")
tell process "Script Editor" to click menu item 7 of menu of menu item 14 of menu 4 of menu bar 1
end tell
compile front document
save front document
close front document
end tell
This script opens the script, it does the search, replaces, clicks on "replace" menu, then it compiles new version, saves it and closes it. If you have many scripts, you must run it through a loop for each script.
I tested it OK with simple line : replace "Set B to 2" by new line "Set X to 5".
However, your issue is more complex because you want to replace several lines, not only 1. I did not found a way to set the search area with multiple lines. I tried with CR (13) or LF (10), but it does not work. May be someone has an idea for that part ?
Also, if you want to add a " in your search or replace patterns, you can use the following :
set Guil to ASCII character 34
Set CurString to "this is a " & Guil & "s" & Guil & " between quotes"
In this case, the CurString value will be : this is a "s" between quotes
I purchased Script Debugger from Late Night Software and it enables the script to access pieces of code and replace them. Mark Alldritt was amazing in the support he offered and the software is now my "first use" destination.
You are sure of your original script and the final script? In this case no hesitation to use xxd and sed below in hexadecimal script which you wrote you can test this script, no danger for your script. Naturally, you change your path and names at your convenience.
set thePath to POSIX path of (choose file)
tell application "Script Editor"
set doc to open thePath
save doc as "text" in POSIX file "/Users/yourname/Desktop/yourscriptold.txt"
close thePath
end tell
set scp to do shell script "xxd -p -c 100000 /Users/yourname/Desktop/yourscriptold.txt " & " | sed -e 's#74656c6c206170706c69636174696f6e202241646f62652050686f746f73686f7020434320323031352e35220a736574206d794c6179657220746f2063757272656e74206c61796572206f662063757272656e7420646f63756d656e740a6966206c61737420636861726163746572206f66206d7953706f727420697320227322207468656e0a73657420636f6e74656e7473206f662074657874206f626a656374206f66206d794c6179657220746f206d7953706f727420262022220a656c73650a73657420636f6e74656e7473206f662074657874206f626a656374206f66206d794c6179657220746f206d7953706f7274202620222773220a656e642069660a656e642074656c6c#74656c6c206170706c69636174696f6e202241646f62652050686f746f73686f7020434320323031352e35220a736574206d794c6179657220746f2063757272656e74206c61796572206f662063757272656e7420646f63756d656e740a73657420636f6e74656e7473206f662074657874206f626a656374206f66206d794c6179657220746f206d7953706f7274202620222773220a656e642074656c6c#' > /Users/yourname/Desktop/yourscriptnew.txt"
set scp to do shell script "xxd -r -p /Users/yourname/Desktop/yourscriptnew.txt >/Users/yourname/Desktop/yournewscript.txt"
do shell script "osacompile -o " & "/Users/yourname/Desktop/temporyname.scpt" & " /Users/yourname/Desktop/yournewscript.txt"
do shell script "rm -f /Users/yourname/Desktop/yourscriptold.txt "
do shell script "rm -f /Users/yourname/Desktop/yourscriptnew.txt "
do shell script "rm -f /Users/yourname/Desktop/yournewscript.txt "

How do I make my AppleScript detect when I move its application?

So, I am trying to create an app with AppleScript, but when I move my app in a different folder and run it, it always will look at the folder it was in before.
display dialog "Kindle Fire HDX 7" Utility Mac
Please select the action you want to do.
Make sure a Terminal window is OPENED!!!"
buttons {"Connected Devices", "Reboot", "More..."} default button 3
set the button_pressed to the button returned of the result
if the button_pressed is "Connected Devices" then
-- action for 1st button goes here
tell application "Terminal"
VVVV Right here is error
if (count of windows) is not 0 then
do script "cd ~/Desktop/ADB-GUI/Kindle Fire HDX 7" Utility.app/Contents/Resources/minerboyadb/ && ./adb devices"
^^^^ Right here is error
end if
else if the button_pressed is "" then
-- action for 2nd button goes here
else
-- action for 3rd button goes here
end if
Is there a way to fix this? Or is it possible to use Xcode to make an AppleScript app? (Which might work better.)
Your code, as posted as of this writing, won't compile, but to answer the question in general:
POSIX path of (path to me)
will return the POSIX path to the running AppleScript-based application from within it, including a trailing /; e.g.: "/Applications/MyAppleScriptApp.app/"
Aside from that, you should always use quoted form of when adding an argument to a shell-command string for use with do script or do shell script, so as to ensure that it is preserved as-is and doesn't break the overall shell command.
Furthermore, assuming your intent is to simply display/capture the output from a shell command, use do shell script, which runs a shell command hidden and returns its stdout output; e.g.:
set cmdOutput to do shell script "ls"
display alert "Files in current folder" message cmdOutput

wait for command line program execution before issuing new action in AppleScript

I am pretty new to AppleScript. I need a script that opens 3 iTerm tabs and executes 3 command line programs respectively. The first program terminates, while the last 2 run indeterminately.
Here is what I have:
tell application "iTerm"
activate
set next to (make new terminal)
tell next
activate current session
launch session "Default Session"
tell the last session
set name to "vagrant-db"
write text "cd ~/Workspace/vagrant-db; vagrant up"
end tell
launch session "Default Session"
tell the last session
set name to "next/core"
write text "cd ~/Workspace/next"
write text "/usr/local/bin/sbt \"project core\" \"run\""
end tell
launch session "Default Session"
tell the last session
set name to "next/web"
write text "cd ~/Workspace/next"
write text "/usr/local/bin/sbt \"project web\" \"~re-start\""
end tell
end tell
end tell
Problem is I need to wait for the first command line operation to end (vagrant booting up) before issuing the second and third. Is there a way to do it?
Not sure if it is possible, but maybe using "do shell script" command from applescript instead, e.g.
set response to do shell script "ls"
will return the contents of the root folder.
Another way (but a very ugly one) is to use 'delay'. E.g.
delay 5
Will delay for 5 seconds
solved with something like
--first program exec
set a to 0
repeat until (a = 1)
if (text of current session contains "ready") then
set a to 1
end if
end repeat
--second program exec
--third program exec
Rusty's answer worked for me. I'm adding this answer to provide detail requested by fusio (sorry, I'd rather have provided this as comment, but comments require more reputation points than adding a new answer).
Rusty's answer requires already being in the context of talking to the current window.
on wait_for(str)
tell application "iTerm"
tell current window
set a to 0
repeat until (a = 1)
if (text of current session contains str) then
set a to 1
end if
end repeat
end tell
end tell
end wait_for
Then, in your code, call:
my wait_for("Provisioners marked to run always will still run.")
The above argument occurs later than "ready".
This is still plenty ugly, but it works.

Combining two scripts in applescript

I'm a complete newbie to applescript and my new external backup HDD made it necessary for me to work with it. As it is quite noisy I wanted to write a script that mounts the disk (if it is unmounted), runs the backup and then ejects the backup disk again (Code A). So far so good. In order to eject the disk after backup has finished I found a piece of code to check if a process is still running (Code B). It returns 1 if the backup process (backupd) is still alive and 0 if it is finished.
I am struggling now with combining those two pieces. I would like code B to keep checking after the backup has started if backupd is still running and if it is done go to the next step and eject the disk.
I just can't get code B running in code A and also the needed loop confuses me a bit. Any help is really greatly appreciated!! I can't imagine it's that tricky just too much for my imagination Thanks for helping me restoring peace and quietness
Code A:
set myVolumeLabel to "Time Machine"
tell application "Finder"
set diskDev to do shell script "diskutil list | grep \"" & myVolumeLabel & "\" | grep -o > 'disk[0-9]*' "
if not (disk myVolumeLabel exists) then
do shell script "diskutil mountDisk " & diskDev
do shell script "/System/Library/CoreServices/backupd.bundle/Contents/Resources/backupd-> helper >/dev/null 2>&1 &"
(* Checking if the backupd process is still running should go here I suppose.*)
else
do shell script "diskutil eject /Volumes/'Time Machine' " & diskDev
end if
end tell
Code B
on check_process(marker)
set the_processes to (do shell script "ps -A")
return (the_processes contains marker)
end check_process
if check_process("/backupd") then
set x to "1"
else
set x to "0"
end if
---display dialog x buttons {"OK"} default button 1
Mac OS X (10.6.8)
It seems to me that what you want to do is rather low-level kind of "system stuff" and that more of the code should be done in the shell.
I'm learning both AppleScript and Unix shell-scripting (the bash shell to be precise, which is the default shell in OS X).
Most of your AppleScript here is really mostly shell scripts inside of AppleScript.
It seems like in this case, the right tool for the right job is a shell script.
You may not want to learn a whole 'nother programming language right now, so I'll give you a couple of thoughts.
If you end a shell-command with an ampersand "&" inside of the quotation marks, then AppleScript will NOT wait for the shell script to complete but rather it will return immediately, putting the process on a separate thread and will return a process id.
If you don't terminate a shell-command with an ampersand, then AppleScript will wait for the command to finish before proceeding.
You can try the following experiment. Type in the following command into Terminal.app:
sleep 10
It will take 10 seconds before you get control back in Terminal.
If you type the following command,
sleep 10&
You will get control back immediately and will get a process id back to refer to the process which you have started.
Well, again, it seems to me that the whole script is best written as a bash script, possibly using a little bit of Automator or AppleScript to kick things off.
Mac shell (bash) tutorial:
http://tidbits.com/article/7003
-- Kaydell
Let me be your guide

How to run multiple script files in a sequence on OS X?

I have 10 script files and each file contain up to 100 commands ( each command take 1 min ). At the moment it saves me time and I click only one file to execute 100 commands but what I want is another script file which execute 10 script files sequentially instead of me waiting for each to finish and then executing the second script file by clicking it.
You just call each script as you would before, but seperate them with a semicolon ;
After each script finishes execution, bash will start executing the next script.
In the terminal:
./scriptsrc/script_1; ./scriptsrc/script_2; ./scriptsrc/script_n;
If you need more guidance check this question out, its fairly similar.
EDIT:
If you want to run multiple scripts from one other script this can be accomplished by adding the shebang line to tell the kernel the file is executable and then just listing what scripts you want:
#!/bin/bash
./scriptsrc/script_1
./scriptsrc/script_2
./scriptsrc/script_n
echo "script execution complete"
set a to alias POSIX file "/Users/Firebird/Documents/script1.scpt"
set b to alias POSIX file "/Users/Firebird/Documents/script2.scpt"
set c to alias POSIX file "/Users/Firebird/Documents/script3.scpt"
set theScriptFiles to {a, b, c}
repeat with scriptFile in theScriptFiles
run script scriptFile
end repeat
The last script on the list didn't run the first couple of times when I was testing for an unknown reason, but after I ran
set myList to {"Hello", "Goodbye", "I must be going"}
repeat with theItem in myList
say theItem
end repeat
it worked!
To make sure all the scripts ran I tell Texteditor to open a file for each corresponding script:
tell application "Finder" to open "Macintosh:Users:Firebird:Documents:ranscript1.rtf"
This thread is really good too from MacScripter http://macscripter.net/viewtopic.php?id=44260

Resources