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
Related
I may have inadvertently launched a bash script containing an infinite cycle whose exit condition may be met next century, if ever. The fact is that I launched the script, as I would do with a nohup program, with
bash [scriptname].sh &
so that (as I get it, which is most probably wrong) I can close the terminal and still keep the script running, as was my intention in developing it. The script should run calculation programmes in my absence and let me gather the results after some time.
Now I want to stop it, but nothing seems to do the trick: I killed the programmes the script had launched, I removed the input file the script was getting orders from and - last and most perfect of accomplishments - I accidentally closed the terminal trying to "exit" the script, which was still giving me error messages.
How can I check whether the script is running (as it does not appear in "top")? Is the '&' relevant? Should I just ask permission to reboot the pc, if that will work and kill everything?
Thank you.
[I put a "Hi everyone" at the beginning but the editor won't let me show it. Oh, well. It's that kind of day.]
Ok, I'll put it right here to prove my stupidity, as I wandered the internet shortly (after a long wandering before writing this post) and found that the line:
kill -9 $(pgrep -f [SCRIPTNAME].sh)
does the trick from any terminal window.
I write this answer to help anyone in the same situation, but feel free to remove the thread if unnecessary (and excuse me for disturbing).
Good you found it, here is another way if you do not use bash -c and run it in current shell not a separate shell.
# put a job in background
sleep 100 &
# save the last PID of background job
MY_PID=$!
# later
kill $MY_PID
I am having a problem where c:\processes are still running after my applications end in wineskin.
I use wineskin to run all of my windows games on my mac and noticed just now that my mac was not cooling down.
An inspection of activity monitor showed me that processes with the location c:\ were still running and I know that obviously mac doesn't run these on its own.
Particularly, one of these processes was using 59% of CPU resulting in the heat up, even though I was done playing my games at least an hour beforehand.
Is there a way for me to tie these processes together so when dirt3_game.exe or whatever else ends, all of the constituent wineskin processes end too?
Or click a button that kills all these in one go after I'm done playing?
Is there a way to write a command in terminal, or a script or something that allows me to end all C: commands?
Just for reference a screenshot is attached so you can see these processes...as you can see
With the game running (or stuck), find out the name of the process looking in the Activity Monitor. Then using Script Editor, write a little applet that kills the process. Here's an example for Ghost Recon-
--Option A
try
set pid_ to do shell script "pgrep 'Ghost Recon384054366Wine'"
do shell script "kill -9 " & pid_
end try
--Option B
tell application "System Events"
set PID_list to (unix id of every process whose name contains "Ghost")
end tell
repeat with x from 1 to (count PID_list)
do shell script "kill -9 " & (item x of PID_list)
end repeat
I'm new to AppleScript but I have to recreate a batch file which I have written for Windows in OSX and AppleScript seems the best way to do this. Basically, the script will created by another program dynamically and then executed. The AppleScript simply needs to wait for a process, which I want to identify by its process ID, and display a message if the process is still running after a specific amount of time.
Is this possible, and if so, how?
Thanks in advance
I eventually found a solution to my given problem after searching online a bit more. Here is the AppleScript code I use to check if a process with a given id pid is running
tell application "System Events"
set runningApplications to (unix id of every process)
if (runningApplications contains (pid as integer)) is false then
-- process is not running
else
-- process still running
end if
end tell
This is just a snippet obviously. Personally I have the above the statement in a repeat loop, but this offers a solution to checking a process id (which is the unix id).
Hope this helps others
Here are some things to (hopefully) get you on your way:
shell scripts in terminal, and 'do shell script' command: don't know how well you know Unix, but you definitely want to go there, and
learn basics of bash. with some limitations, you can run shell
scripts via AS through the 'do shell script' command.
writing the script dynamically: osascript and osacompile will probably come in handy. see the man pages. osascript can execute
scripts or script text, and osacompile can (!) compile text into
script form (non-text form), among other things.
script waiting for/watching process: more shell script stuff, or using the Finder (what used to be called the Scriptable Finder!),
that is, the Finder's scripting capabilities (dictionary), like
tell application "Finder" to get name of processes. The shell version (which can be called via the 'do shell script' AS command)
might be "ps ax | grep Safari | grep -v grep | awk '{print $1}'" (taken from
stackoverflow post. I like it because it returns empty string if no
match). Depending on how your main script will run, learn how the
idle handler works in a script application, and how that differs from
using an xcode-built app (if that's the route you go), or just a
script.
displaying a message: 'display dialog' is the super simple method, complete with timeout ("gives up" after n seconds). (Sorry if this is
so basic I just insulted your intelligence :-) )
other: Check out (unless you're already wedded to a script editing environment) Smile. It's my primary script editor.
What I have is an applescript app in xcode that runs a shell script. What I was hoping to do is have the progressIndicator move a certain amount when the command is "echo hello world" as an example but since all of my commands are sudo I have to put them in a shell script together and I can't just have the progressIndicator move in between commands (there are lots of them.) Is there a way to have the bar move when a certain command is started? Also, is there a way to output the log of the applescript to a textView in xcode?
You can always run the command line tool "ps" to see which processes are currently running. As such you can formulate a repeat loop and using ps can figure out which of your commands are currently running... and thus increment your progress indicator as needed.
Here's a ps command I've used to get a nice listing. You can combine this with grep to filter for your processes...
/bin/ps -Axcro user,pid,%cpu,command
Hi. I'm new to the shell and am working on my first kludged together script. I've read all over the intertube and SO and there are many, MANY places where disown, nohup, & and return are explained but something isn't working for me.
I want a simpler timer. The script asks for user input for the hours, mins., etc., then:
echo "No problem, see you then…"
sleep $[a*3600+b*60+c]
At this point (either on the first or second lines, not sure) I want the script OR the specific command in the script to become a background process. Maybe a daemon? So that the timer will still go off on schedule even if
that terminal window is shut
the terminal app is quit completely
the computer is put to sleep (I realize I probably need some different code still to wake the mac itself)
Also after the "No problem" line I want a return command so that the existing shell window is still useful in the meantime.
The terminal-notifier command (the timer wakeup) is getting called immediately under certain usage of the above (I can't remember which right now), then a second notification at the right time. Using the return command anywhere basically seems to quit the script.
One thing I'm not clear on is whether/how disown, nohup, etc. are applicable to a command process vs. a script process, i.e., will any of them work properly on only a command inside a script (and if not, how to initialize a script as a background process that still asks for input).
Maybe I should use some alternative to sleep?
It isn't necessary to use a separate script or have the script run itself in order to get part of it to run in the background.
A much simpler way is to place the portions that you want to be backgrounded (the sleep and following command) inside of parentheses, and put an ampersand after them.
So the end of the script would look like:
(
sleep $time
# Do whatever
)&
This will cause that portion of the code to be run inside a subshell which is placed into the background, since there's no code after that the first shell will immediately exit returning control to your interactive shell.
When your script is run, it is actually run by starting a new shell to execute it. In order for you to get your script into the background, you would need to send that shell into the background, which you can't do because you would need to communicate with its parent shell.
What you can do is have your script call itself with a special argument to indicate that it should do the work:
#! /bin/zsh
if [ "$1" != '--run' ] ; then
echo sending to background
$0 --run $# &
exit
fi
sleep 1
echo backgrounded $#
This script first checks to see if its first argument is --run. If it is not, then it calls itself ($0) with that argument and all other arguments it received ($#) in the background, and exits. You can use a similar method, performing the test when you want to enter the background, and possibly sending the data you will need instead of every argument. For example, to send just the number of seconds:
$0 --run $[a*3600+b*60+c] &