How to run multiple shell scripts from applescript in background - applescript

I am launching an a jar application from apple script.
do shell script quoted form of jvmpath & " -jar -XstartOnFirstThread -Dapple.awt.UIElement=true -Dfile.encoding=UTF8 " & quoted form of jarpath & " " & quoted form of parameters
The script keeps running till i quit my jar application.
But i am required to launch another application form shell script.
Since i am doing this in a Cocoa app i want to do this in the background.
Thus, can i launch multiple scripts in multiple instances of terminal (so that they aren't blocking one another).
Note: I tested it by running the command in two different terminal windows, works as expected.

See Technical Note TN2065, specifically the answers to the questions "I want to start a background server process; how do I make do shell script not wait until the command completes?" and "I have started a background process; how do I get its process ID so I can control it with other shell commands?".
The AppleScript code to run two commands in the background would look like this:
set pid1 to do shell script command1 & " &> /dev/null & echo $!"
set pid2 to do shell script command2 & " &> /dev/null & echo $!"
The pid1 and pid2 variables will be set to the process ids of the two commands. You can later check whether the commands are still running by calling a function like this one:
on isProcessRunning(pid)
try
do shell script "kill -0 " & pid
set isRunning to true
on error
set isRunning to false
end try
return isRunning
end isProcessRunning

Related

Why does this nested bash command with subshells hang? [duplicate]

I have a script (lets call it parent.sh) that makes 2 calls to a second script (child.sh) that runs a java process. The child.sh scripts are run in the background by placing an & at the end of the line in parent.sh. However, when i run parent.sh, i need to press Ctrl+C to return to the terminal screen. What is the reason for this? Is it something to do with the fact that the child.sh processes are running under the parent.sh process. So the parent.sh doesn't die until the childs do?
parent.sh
#!/bin/bash
child.sh param1a param2a &
child.sh param1b param2b &
exit 0
child.sh
#!/bin/bash
java com.test.Main
echo "Main Process Stopped" | mail -s "WARNING-Main Process is down." user#email.com
As you can see, I don't want to run the java process in the background because i want to send a mail out when the process dies. Doing it as above works fine from a functional standpoint, but i would like to know how i can get it to return to the terminal after executing parent.sh.
What i ended up doing was to make to change parent.sh to the following
#!/bin/bash
child.sh param1a param2a > startup.log &
child.sh param1b param2b > startup2.log &
exit 0
I would not have come to this solution without your suggestions and root cause analysis of the issue. Thanks!
And apologies for my inaccurate comment. (There was no input, I answered from memory and I remembered incorrectly.)
The following link from the Linux Documentation Project suggests adding a wait after your mail command in child.sh:
http://tldp.org/LDP/abs/html/x9644.html
Summary of the above document
Within a script, running a command in the background with an ampersand (&)
may cause the script to hang until ENTER is hit. This seems to occur with
commands that write to stdout. It can be a major annoyance.
....
....
As Walter Brameld IV explains it:
As far as I can tell, such scripts don't actually hang. It just
seems that they do because the background command writes text to
the console after the prompt. The user gets the impression that
the prompt was never displayed. Here's the sequence of events:
Script launches background command.
Script exits.
Shell displays the prompt.
Background command continues running and writing text to the
console.
Background command finishes.
User doesn't see a prompt at the bottom of the output, thinks script
is hanging.
If you change child.sh to look like the following you shouldn't experience this annoyance:
#!/bin/bash
java com.test.Main
echo "Main Process Stopped" | mail -s "WARNING-Main Process is down." user#gmail.com
wait
Or as #SebastianStigler states in a comment to your question above:
Add a > /dev/null at the end of the line with mail. mail will otherwise try to start its interactive mode.
This will cause the mail command to write to /dev/null rather than stdout which should also stop this annoyance.
Hope this helps
The process was still linked to the controlling terminal because STDOUT needs somewhere to go. You solved that problem by redirecting to a file ( > startup.log ).
If you're not interested in the output, discard STDOUT completely ( >/dev/null ).
If you're not interested in errors, either, discard both ( &>/dev/null ).
If you want the processes to keep running even after you log out of your terminal, use nohup — that effectively disconnects them from what you are doing and leaves them to quietly run in the background until you reboot your machine (or otherwise kill them).
nohup child.sh param1a param2a &>/dev/null &

Running bash script does not return to terminal when using ampersand (&) to run a subprocess in the background

I have a script (lets call it parent.sh) that makes 2 calls to a second script (child.sh) that runs a java process. The child.sh scripts are run in the background by placing an & at the end of the line in parent.sh. However, when i run parent.sh, i need to press Ctrl+C to return to the terminal screen. What is the reason for this? Is it something to do with the fact that the child.sh processes are running under the parent.sh process. So the parent.sh doesn't die until the childs do?
parent.sh
#!/bin/bash
child.sh param1a param2a &
child.sh param1b param2b &
exit 0
child.sh
#!/bin/bash
java com.test.Main
echo "Main Process Stopped" | mail -s "WARNING-Main Process is down." user#email.com
As you can see, I don't want to run the java process in the background because i want to send a mail out when the process dies. Doing it as above works fine from a functional standpoint, but i would like to know how i can get it to return to the terminal after executing parent.sh.
What i ended up doing was to make to change parent.sh to the following
#!/bin/bash
child.sh param1a param2a > startup.log &
child.sh param1b param2b > startup2.log &
exit 0
I would not have come to this solution without your suggestions and root cause analysis of the issue. Thanks!
And apologies for my inaccurate comment. (There was no input, I answered from memory and I remembered incorrectly.)
The following link from the Linux Documentation Project suggests adding a wait after your mail command in child.sh:
http://tldp.org/LDP/abs/html/x9644.html
Summary of the above document
Within a script, running a command in the background with an ampersand (&)
may cause the script to hang until ENTER is hit. This seems to occur with
commands that write to stdout. It can be a major annoyance.
....
....
As Walter Brameld IV explains it:
As far as I can tell, such scripts don't actually hang. It just
seems that they do because the background command writes text to
the console after the prompt. The user gets the impression that
the prompt was never displayed. Here's the sequence of events:
Script launches background command.
Script exits.
Shell displays the prompt.
Background command continues running and writing text to the
console.
Background command finishes.
User doesn't see a prompt at the bottom of the output, thinks script
is hanging.
If you change child.sh to look like the following you shouldn't experience this annoyance:
#!/bin/bash
java com.test.Main
echo "Main Process Stopped" | mail -s "WARNING-Main Process is down." user#gmail.com
wait
Or as #SebastianStigler states in a comment to your question above:
Add a > /dev/null at the end of the line with mail. mail will otherwise try to start its interactive mode.
This will cause the mail command to write to /dev/null rather than stdout which should also stop this annoyance.
Hope this helps
The process was still linked to the controlling terminal because STDOUT needs somewhere to go. You solved that problem by redirecting to a file ( > startup.log ).
If you're not interested in the output, discard STDOUT completely ( >/dev/null ).
If you're not interested in errors, either, discard both ( &>/dev/null ).
If you want the processes to keep running even after you log out of your terminal, use nohup — that effectively disconnects them from what you are doing and leaves them to quietly run in the background until you reboot your machine (or otherwise kill them).
nohup child.sh param1a param2a &>/dev/null &

How to run shellscript parallely like java thread

Hi I have a script mainscript.sh
In main script I have multiple chile script.
child1.sh
child2.sh
child3.sh
rm -rf /home/bdata/batch/*
I am running my mainscript.sh which will run all child jobs in parallel.
mainscript.sh
child1.sh &
child2.sh &
child3.sh &
rm -rf /home/bdata/batch/*
4th statement runs before completing all the execution.
Is there any way I can control the execution of last line after finishing above 3 scripts in parallel.
Simply tell the shell to wait until the children are all dead:
child1.sh &
child2.sh &
child3.sh &
wait
rm -rf /home/bdata/batch/*
This is one solution:
#!/bin/bash
./child1.sh &
./child2.sh &
./child3.sh &
Use ./ or full path to the script.
If a command is terminated by the control operator &, the shell
executes the command in the background in a subshell. The shell does
not wait for the command to finish, and the return status is 0. If you want to execute all child-scripts before exiting the script then add wait at the end (as #Mark Setchell wrote below).

POSIX shell semantic for exec and & (moving program to background)

I can't figure what happen on:
exec CMD &
especially what value for pid is:
echo $!
With exec CMD &, the & takes effect first, so everything is run in background; then the command is evaluated, and exec'd, but that would have happened without the exec, so in fact that is the same as writing CMD & (but causes people to worry about why it was written thus, so it is bad style).
The value in $! should be the PID of the command that is executed in the background.

Using ASObjC Runner to abort a shell script command in Applescript

I've got ASObjC Runner code in my AppleScript that shows a progress window once a do shell script is run. How do I make the button on the progress window kill the shell script?
Heres a sampling of my code:
tell application "ASObjC Runner"
reset progress
set properties of progress window to {button title:"Abort", button visible:true, indeterminate:true}
activate
show progress
end tell
set shellOut to do shell script "blahblahblah"
display dialog shellOut
tell application "ASObjC Runner" to hide progress
tell application "ASObjC Runner" to quit
There are several parts to the answer:
Asynchronous do shell script: normally, do shell script only returns after the shell command has completed, which means you cannot act on the processes inside the shell. However, you can get a do shell script command to execute asynchronously by backgrounding the shell command it executes, i.e.
do shell script "some_command &> /target/output &"
– which will return immediately after launching the shell command. As it will not return the command’s output, you have to catch that yourself, for instance in a file (or redirect to /dev/null if you don’t need it). If you append echo $! to the command, do shell script will return the PID of the background process. Basically, do
set thePID to do shell script "some_command &> /target/output & echo $!"
see Apple’s Technical Note TN2065. Stopping that process is then a simple matter of doing do shell script "kill " & thePID.
Hooking into ASObjC Runner’s progress dialog is just a matter of polling its button was pressed property and breaking on true:
repeat until (button was pressed of progress window)
delay 0.5
end repeat
if (button was pressed of progress window) then do shell script "kill " & thePID
Deciding when your shell script is done to dismiss the progress dialog: that is the interesting part, as the shell command operates asynchronously. Your best bet is to shell out to ps with the PID you retrieved to check if the process is still running, i.e.
if (do shell script "ps -o comm= -p " & thePID & "; exit 0") is ""
will return true when the process is not running anymore.
Which leaves you with the following code:
tell application "ASObjC Runner"
reset progress
set properties of progress window to {button title:"Abort", button visible:true, indeterminate:true}
activate
show progress
try -- so we can cancel the dialog display on error
set thePID to do shell script "blahblahblah &> /file/descriptor & echo $!"
repeat until (button was pressed of progress window)
tell me to if (do shell script "ps -o comm= -p " & thePID & "; exit 0") is "" then exit repeat
delay 0.5 -- higher values will make dismissing the dialog less responsive
end repeat
if (button was pressed of progress window) then tell me to do shell script "kill " & thePID
end try
hide progress
quit
end tell
If you need to capture the output of your background shell command, you will have to redirect it to file and read out that file’s content when done, as noted above.

Resources