How to Wait for First Command to Finish

how to wait for first command to finish?

Shell scripts, no matter how they are executed, execute one command after the other. So your code will execute results.sh after the last command of st_new.sh has finished.

Now there is a special command which messes this up: &

cmd &

means: "Start a new background process and execute cmd in it. After starting the background process, immediately continue with the next command in the script."

That means & doesn't wait for cmd to do it's work. My guess is that st_new.sh contains such a command. If that is the case, then you need to modify the script:

cmd &
BACK_PID=$!

This puts the process ID (PID) of the new background process in the variable BACK_PID. You can then wait for it to end:

while kill -0 $BACK_PID ; do
echo "Process is still active..."
sleep 1
# You can add a timeout here if you want
done

or, if you don't want any special handling/output simply

wait $BACK_PID

Note that some programs automatically start a background process when you run them, even if you omit the &. Check the documentation, they often have an option to write their PID to a file or you can run them in the foreground with an option and then use the shell's & command instead to get the PID.

wait one process to finish and execute another process

You can achieve a simple way of process synchronization in bash using wait which waits for one or more number of background jobs to complete before running the next.

You generally run jobs in the background by appending the & operator to the end of a command. At that point the PID (process ID) of the newly created background process is stored in a special bash variable: $! and wait command allows this process to be terminate before running the next instruction.

This can be demonstrated by a simple example

$ cat mywaitscript.sh

#!/bin/bash

sleep 3 &

wait $! # Can also be stored in a variable as pid=$!

# Waits until the process 'sleep 3' is completed. Here the wait on a single process is done by capturing its process id

echo "I am waking up"

sleep 4 &
sleep 5 &

wait # Without specifying the id, just 'wait' waits until all jobs started on the background is complete.

echo "I woke up again"

Command ouput

$ time ./mywaitscript.sh
I am waking up
I woke up again

real 0m8.012s
user 0m0.004s
sys 0m0.006s

You can see the script has taken ~8s to run to completion. The breakdown on the time is

  1. sleep 3 will take full 3s to complete its execution

  2. sleep 4 and sleep 5 are both started sequentially one after next and it has taken the max(4,5) which is approximately ~5s to run.

You can apply the similar logic to your question above. Hope this answers your question.

Make Popen wait for first command to finish then start next

After glancing over the readme for this nuke module, I get the sense that you might be confused about what is actually required to use it.

subprocess.Popen(['X:\\apps\\Nuke6.1v5\\Nuke6.1.exe', '-t', 'X:\\apps\\Scripts\NUKE\\nukeExternalControl\\server.py'])

... This line (which I assume you are actually assigning to a variable and either blocking on it, or checking its status), is what is required to start a non-gui based server with Nuke. Nuke being a python interpreter can run a python script via nuke -t <script.py>, hence you are using it to start your server process. This will block, and wait for you to use your client class to communicate.

What seems to be missing from your question is more context about how you are exactly trying to run this server/client configuration. If you are attempting to do both parts in the same script, then you would need to start the server process as you are doing, then maybe sleep for a second (the server process starts pretty quickly), and then run the client code that makes the connection.

Update

Realistically there are two ways to start your server process, as very plainly outlined in the readme:

To start a command sever whenever Nuke is launched, add the following lines
to your Nuke menu.py:
---------------------------
import nukeExternalControl.server
nukeExternalControl.server.nuke_command_server()
---------------------------

This is something you would put in your nuke menu.py file, or manually start this with a running Nuke application. Your application will now be running a server process and allow clients to connect.

If you dont want to have to use a GUI license and keep it running to server connections, then you use the other method from the command line X:\apps\Nuke6.1v5\Nuke6.1.exe -t X:\apps\Scripts\NUKE\nukeExternalControl\server.py , which starts a terminal-based server. There is NO reason I can think of that you need to be using subprocess to start the server in your script when they give you a method for starting it already.

Solution

After a lengthy conversation with the OP, it turns out that what he wanted to do was what the first part of my answer suggested. He has a standalone script that wants to do something using Nuke's python interpreter (completely headless without the Nuke GUI app). Using this 3rd party module, he wants to start the script in a subprocess that will act as a server to the nuke terminal. He will then proceed in his code to communicate with it using the client class (he is self hosting a server process and sorta round-robin communicating with it.

The solution to his problem was that he needed to time.sleep(2) right after the Popen that starts his server.py. Waiting a few seconds for the server to completely start allowed the client to successfully connect.

And yes, he owes me a beer now.

How to wait in bash for several subprocesses to finish, and return exit code !=0 when any subprocess ends with code !=0?

wait also (optionally) takes the PID of the process to wait for, and with $! you get the PID of the last command launched in the background.
Modify the loop to store the PID of each spawned sub-process into an array, and then loop again waiting on each PID.

# run processes and store pids in array
for i in $n_procs; do
./procs[${i}] &
pids[${i}]=$!
done

# wait for all pids
for pid in ${pids[*]}; do
wait $pid
done

Wait for command to finish / window to close in Bash

In this case, your script is behaving properly. By doing this:

lxterminal --title="mytitle" --geometry=200x200 -e "./myapplication" &
PID=$!
wait $PID

Wait will use the PID of the last command used (lxterminal). However, you are interested in child process which would be the PID of ./myapplication running itself. Basically, lxterminal will have its own PID and as parent, it will launch your script and it will create a new process with its new PID (child).

So the question would be, how to retrieve the PID child process given the parent child?

In your case, we can use next command.

ps --ppid $PID

Which will give such output.

ps --ppid 11944
PID TTY TIME CMD
11945 pts/1 00:00:00 sleep

Then, with some help, we can retrieve only the child PID.

ps --ppid 11944 | tail -1 | cut -f1 -d" "
11945

So finally, in your script, you can add new variable containing child process.

#!/bin/bash

while true
do
lxterminal --title="mytitle" --geometry=200x200 -e "./myapplication" &
PID=$!
CPID=ps --ppid $PID | tail -1 | cut -f1 -d" "
wait $CPID
done

I did not really try it in your case, as I don't have same scenario than yours, but I believe it should work, if not, there might be some hints in this answer which might help you to find proper solution to your problem.



Related Topics



Leave a reply



Submit