1

In my script, I have the following: cat list | xargs -P6 -n2 ./first_queue & where list is just a file with pairs of words that I want to process:

word1 word2

word3 word4

etc...

first_queue is just another script. I am trying to get the pid of all 6 processes that are spawned by this xargs right after I call it so that I can later terminate them. I read that $!gives the pid of the last process that ran in the background. However, I want all 6 of them. How can I get them?

More details:

I wrote the following small script to test what @xenoid suggested:

cat list | xargs -P6 -n2 ./first_queue &
id=$(echo $!)
echo $id
ids=$(pgrep -P $id)
echo $ids
ps aux | grep $id
for x in $ids; do
    echo $x
    ps aux | grep $x
    kill $x
done
kill $id
ps aux | grep $id
for x in $ids; do
    ps aux | grep $x
done

Here is first_queue extremely simplified (to the command that is giving me the trouble, and that keeps running despite running kill on the parent process i.e xargs as well as the child processes):

srr=$1
bioproject=$2

prefetch $srr -O download_dir/$bioproject

prefetch just downloads data from an online database.

1 Answer 1

0

The PID you get with $! is xargs's own PID (because this is xargs that you are sending to the background...), not the one of your processes. If you terminate it it will terminate all its children (i.e., any of your processes still running).

If you want the pids of the child processes you can use pgrep -P {parent} where {parent} is xargs PID.

Edit:

When you run a command (pid=Y) in a script (pid=X), and send a signal to the script (to pid=X), the signal is not forwarded to the command (so pid=Y doesn't see it).

You can write a contrived script that starts the command in the background, grabs its pid (Y), traps signals send to pid=X and forwards them to pid=Y.

But in many cases, the command is the last significant bit of code to run (the script exits with the command's return code). When this is so instead of using:

some_initialization_code
the_command and the command args
exit $?

you write your script as:

some_initialization_code
exec the_command and the command args

In the first case the script is the process with pid=X and the command is the process with pid=Y. With exec, process with pid=X becomes the command, and everything happens as if you called the_command directly: there is no pid=Y, and signals sent to process X (the script) are received by the the_command when it runs.

4
  • so I ended up trying this out but it didn't quite work as I expected. In particular, killing the xargs process did not kill the other processes Jul 15, 2020 at 16:00
  • Worked for me... But if the child processs are calling some other app for the grunt work, the signals may not be forwarded thru. This can be fixed by having the scripts exec the application (then the bash instance is replaced by the application instead of spawning it). Otherwise did you try the other solution?
    – xenoid
    Jul 15, 2020 at 16:29
  • So I'm not very familiar with using exec but after reading about it I don't think it'll work for me because I don't want the script calling it to be replaced by the call. I tried getting the child processes and killing those. That didn't stop the command from being executed. Let me add some details to my question about my specific use case, that'll help Jul 15, 2020 at 17:25
  • 1
    See augmented answer. But IMHO having to routinely kill your processes is a strange design...
    – xenoid
    Jul 15, 2020 at 20:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .