I'm having a problem with the types when getting a getting a return value back from a do shell script.
I'm checking if there are still running unix processes of rsync
repeat until (do shell script "/bin/ps -ef | /usr/bin/grep -c [r]sync") > 0
delay 120
end repeat
tell application "Terminal" to quit
The value thats coming back is correct: --> "4" but the script goes direct to the quit.
I don't know how to set the right types, I have already tried:
repeat until (do shell script "/bin/ps -ef | /usr/bin/grep -c [r]sync") > "0"
But the result is the same.
You misinterpreted the behavior of repeat until: The loop is repeated as long as the condition is not true. As you already have running processes, your condition will yield true and thus, the inner part (delay 120) won't be executed.
What you want is to repeat the loop as long as there are running processes. So you need to compare with = 0 instead of > 0.
So you can either write:
repeat until (do shell script "/bin/ps -ef | /usr/bin/grep -c [r]sync") = "0"
or you can stick with your condition and use a while loop that expresses a "as long as" condition:
repeat while (do shell script "/bin/ps -ef | /usr/bin/grep -c [r]sync") > "0"
Are you sure you have that condition set the way you want it? Your logic is to repeat until the result is greater than 0. But if the result is greater than zero, then there are still sync processes running. For example, you say that the result is sometimes 4. When the result is 4, this simplifies to:
repeat until 4 > 0
delay 120
end repeat
tell application "Terminal" to quit
Since 4 is greater than 0, the condition has been met: it will no longer repeat, since it is only repeating until the value is greater than zero, which it is. Thus, it falls through to the next step, which is to tell the Terminal to quit.
I think you want either a repeat while value > 0, or a repeat until value = 0.
Related
I saw here the use of:
while ps | grep " $my_pid "
Question: In this kind of syntax while -command-, what is the while loop checking, return code of the command or stdout?
It's checking the return value of the process pipeline, which happens to be the return value of the last element in that pipeline (unless pipefail is set, but it usually isn't). The bash doco has this to say:
while list-1; do list-2; done
The while command continuously executes the list list-2 as long as the last command in the list list-1 returns an exit status of zero.
Elsewhere, it states:
The return status of a pipeline is the exit status of the last command
So this while statement continues as long as grep returns zero. And the grep doco states:
The exit status is 0 if a line is selected.
So the intent is almost certainly to keep looping as long as the process you're monitoring is still alive.
Of course, this is a rather "flaky" way of detecting if your process is still running. For a start, if my_pid is equal to 60, that grep is going to return zero if any of the processes 60, 602, or 3060, are running.
It's also going to return zero if, like I often have, you have some number of sleep 60 or sleep 3600 processes in flight, no matter their process ID.
Perhaps a better way, assuming you're on a system with procfs, is to use something like:
while [[ -d /proc/$my_pid ]] ; do ...
This will solve everything but the possibility that process IDs may be recycled so that a different process may start up with the same PID between checks but, since most UNIX-like systems allocate PIDs sequentially with wrap-around, that's very unlikely.
I have this sample code which basically repeats ~20k times. The only thing that changes is the id= in the address and in the echo command line. The id= in the address and the id= in the echo line always correspond. I am running this script on a MAC if that is of any importance.
I would like to improve this script if possible to make it more reliable. Sometimes I either lose connectivity or the session to the server is closed and I am required to log in again but the script keeps running oblivious of the situation. I would like the script to pause if for some reason that happens.
Also after the open command is called, sometimes the server takes longer to responds but the osascript command forces the tab to close after the sleep 2 command has elapsed. This puts me in a position where I am not sure if the server actually took into account the url. Increasing the sleep time is not very reliable. What could be done on that front?
[...]
open 'https://domaineName.com/admin/?adsess=dhnchf6ghd5shak4Dghtfffvw&app=core&module=members&controller=members&do=spam&id=1&status=1' -g
sleep 2
osascript -e 'tell window 1 of application "Safari"
close (tabs where index < (get index of current tab))
end'
echo "done id=1"
open 'https://domaineName.com/admin/?adsess=dhnchf6ghd5shak4Dghtfffvw&app=core&module=members&controller=members&do=spam&id=5&status=1' -g
sleep 2
osascript -e 'tell window 1 of application "Safari"
close (tabs where index < (get index of current tab))
end'
echo "done id=5"
[...]
Any help would be appreciated.
Thank you
You will have to write a script that checks if the main script (lets say main.sh) is currently running on the server (like ps -ef|grep main.sh|grep -v grep)
Check the above output and then execute main.sh inside this script.
This way there is no need for using delay/sleep commands.
I am wondering how I can launch a fresh new Chrome instance (see my script below) that will be brought to the front. Currently the shell script opens the new Chrome instance in the background, which is less than optimal. Executing the shell script from Applescript does nothing to remedy this.
The interesting thing is that if I open Chrome using a shell command directly from AppleScript it seems to open in the foreground:
set q to "'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome' --user-data-dir=/tmp/1234"
do shell script q
Applescript
do shell script "~/bin/chrome-fresh"
Shell script
#!/bin/sh
# This is quite useful for front-enders, as it will launch a fresh
# Chrome instance with no loaded plugins or extensions that messes
# with your performance profiling or network debugging
#
# Install:
# install -m 555 ~/Downloads/chrome-fresh /usr/local/bin/
CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
ARGS="$#"
# make a fresh user directory
TMP_USERDIR=$(mktemp -d);
# avoid the dialog on the first startup
touch "$TMP_USERDIR/First Run";
# start chrome using a fresh user directory
"$CHROME" --user-data-dir="$TMP_USERDIR" "$ARGS"
Run the command in background (put the & at the end of the command).
Use $! to get the process ID of the last command
# start chrome using a fresh user directory
"$CHROME" --activate-on-launch --user-data-dir="$TMP_USERDIR" "$ARGS" &
chromePid=$!
sleep 2
# bring Chrome
osascript -e 'tell application "System Events"' -e "tell (first process whose its unix id is \"$chromePid\" ) to set frontmost to true" -e 'end tell'
In the script bellow, I used a mix of Applescript and Shell commands. I am not Shell expert, so may be there are most efficient way to do it. At least, this script is working :
1) it takes all process containing specific name (i.e. = Chrome)
2) it goes through all found processes, and for each, get the time since it starts using "ps" shell command.
3) it compares that time with previous times found and if lower then it keeps the process information. The lowest time value is linked to the last starting instance of the process.
4) the process with the shortest time since it starts is the last one : it sets the frontmost property to true to make it foreground.
tell application "System Events"
set lastTime to 3600 -- max possible value of start time
set lastPID to -1 -- impossible : used to check if process has been found !
set Prlist to every process whose name contains "Chrome"
repeat with aProc in Prlist
set PStext to do shell script "PS -o etime -p " & unix id of aProc -- get the start time of the process
-- output is dd-hh:mm:ss if process has been stared few days ago
-- output is hh:mm:ss if process has been stared few hours ago
-- output is mm:ss if process has been stared few minutes or seconds ago
-- assumption is made that it just started few seconds ago
-- convert in seconds = mm*60 + ss
set runningTime to ((word 1 of paragraph 2 of PStext) as integer) * 60 + (word 2 of paragraph 2 of PStext) as integer
if runningTime < lastTime then
set lastTime to runningTime
set lastPID to unix id of aProc
set MyProc to aProc
end if
end repeat
if lastPID > 0 then -- if a process has been found
set the frontmost of MyProc to true -- set it in foreground
end if
end tell
I made several comments to make it clear about the "ps" command. If anyone knows how to get directly time in second from ps output, thanks. (I am quite sure there should be an easiest way !)
I am creating an applescript that should wait for two processes to finish and then execute some logic. The first is an Application, which is easy to wait for.
set program to "Applications/xyz.app"
repeat until (application program is not running)
delay 1
end repeat
Now for my background task that doesn't work since it is a directly called executable not an Application. If it helps the process is aria2. Could anyone tell me how this works, or point me in the right direction to find an answer?
Try using pgrep to look for the process id of a process called aria2 like this:
do shell script "/usr/bin/pgrep aria2"
I don't have aria2 so I am only guessing its process name - try it in the Terminal first to see if it works:
pgrep aria2
There will be no output if it is not running.
To see fuller output, run:
ps -aef | grep -i aria
If you want to check it in a loop, you could do this sort of thing:
set ariarunning to 0
repeat until ariarunning > 0
try
set ariarunning to do shell script "/usr/bin/pgrep aria"
end try
delay 1
end repeat
Im trying to write a super simple applescript that will launch the OneDrive App, or ensure it is open, whenever the machine's power source is set to plugged in, and will quit, or make sure is closed, when the power source is set to battery.
I'm having trouble finding how to access the built-in "power indicator" in Yosemite. All of my searches lead to old, irrelevant results from years ago.
Edit: I think I will have to use a do shell script within the applescript using pmset -g batt
Now drawing from 'AC Power'
-InternalBattery-0 100%; charged; 0:00 remaining
And parse this result, but I am not sure how.
Edit: Here it is for anyone in the future who may want something similar:
global appName
on appIsRunning()
tell application "System Events" to (name of processes) contains appName
end appIsRunning
on acIsConnected()
return (do shell script "system_profiler SPPowerDataType | grep -q 'Connected: Yes' && echo \"true\" || echo \"false\"") as boolean
end acIsConnected
on toggleApp()
if my acIsConnected() then
if not my appIsRunning() then
tell application "Finder"
open application file (appName & ".app") of folder "Applications" of startup disk
end tell
end if
else
tell application appName
quit
end tell
end if
end toggleApp
-- This will only be executed once.
on run
set appName to "OneDrive"
end run
-- This will be executed periodically, specified in seconds, every return.
on idle
my toggleApp()
-- Execute every 2 minutes.
return 120
end idle
-- Not mandatory, but useful for cleaning up before quiting.
on quit
-- End handler with the following line.
continue quit
end quit
Here is a one-liner that polls for connected status, since I guess you can have less than 100% and still be connected (charging).
set acConnected to (do shell script "system_profiler SPPowerDataType |grep -q 'Connected: Yes' && echo \"true\" || echo \"false\"") as boolean
Here's another one liner...
set acConnected to last word of paragraph 1 of (do shell script "ioreg -w0 -l | grep ExternalChargeCapable")
If you are happy to use a third party tool, you can avoid polling for the battery state. This will make your script more efficient.
Power Manager can run AppleScripts when the battery state changes. How to Run a Command When Switching to Battery Power, walks through how to set this up for scripts.
Swap out the #!/bin/sh for #!/usr/bin/osascript in the script, and you can use AppleScript.
Disclaimer: I wrote Power Manager and can answer comments about how it works.
Provided you have battery icon on screen's top right:
tell application "System Events" to tell process "SystemUIServer" ¬
to value of attribute "AXDescription" of ¬
(first menu bar item whose value of attribute "AXDescription" ¬
begins with "Battery") of menu bar 1
You get "Battery: Charged" or "Battery: Calculating Time Remaining… " or something else