Fetching the right PID from Process.spawn - ruby

I am creating a CLI application using ruby. This app receives a path to an executable, runs it, fetches the PID and collects stack trace samples every N milliseconds in order to profile the executable.
I use Process.spawn like this:
pid = Process.spwan(ENV, executable)
The problem with pid is that it's not the executable's, but it is the PID of sh -c <EXECUTABLE>.
In order to fetch the right PID I use pidof after Process.spawn like this:
target_pid = `pidof -s #{executable}`
and then I use target_pid for profiling.
Is there a cleaner way to get target_pid using Ruby?

If you don't need the shell then use either of these two forms of calling:
pid = Process.spwan(ENV, executable, '--arg1')
and if you have no arguments then you would need to use this format instead:
pid = Process.spwan(ENV, [executable, 'name of executable'])
If you need the shell then you need to modify your executable variable to do something along these lines
cmd & echo "pid=$!"; fg
which means run your command in the background, obtain the pid of it which you can somehow communicate to your ruby process, then put that process in the foreground again.

Related

Exit a subprocess with ruby

I am trying to write the output of top to a file every 5 seconds which I also got to work.
cmd = "top -s 5 -pid 123 >> top.txt"
p = IO.popen(cmd)
However, the problem I have is that I can't find a way of closing top
I have tried
Process.kill('KILL', p.pid)
but top keeps writing to the output file.
p.close hangs but if I ctrl + c it does seem to exit the top command as well. But this as this requires me to manually ctrl + c it is not a viable solution.
Any help would be appreciated!
The problem is the redirection. >> is a feature of a shell: it starts the process and connects its stdout to the given file. In order for Ruby to do this, it actually starts a shell, which starts top and sets up the redirection.
So p.pid is the PID of the shell, not top. When you kill it, it kills only the shell and top gets disowned, continuing to run under PID 1.
I recommend using Popen3 instead and running just top -s 5 -pid 123 without redirection. This gives you the subprocess as well as its stdout/stderr, so you can manage the output yourself (such as appending it to a file) while being able to kill it.
Alternatively, make a wrapper shell script that runs top with redirection and set it up to kill top when it exits: How do I terminate all the subshell processes? Then have Ruby run that wrapper script.

How to run a shell script with the terminal closed, and stop the script at any time

What I usually do is pause my script, run it in the background and then disown it like
./script
^Z
bg
disown
However, I would like to be able to cancel my script at any time. If I have a script that runs indefinitely, I would like to be able to cancel it after a few hours or a day or whenever I feel like cancelling it.
Since you are having a bit of trouble following along, let's see if we can keep it simple for you. (this presumes you can write to /tmp, change as required). Let's start your script in the background and create a PID file containing the PID of its process.
$ ./script & echo $! > /tmp/scriptPID
You can check the contents of /tmp/scriptPID
$ cat /tmp/scriptPID
######
Where ###### is the PID number of the running ./script process. You can further confirm with pidof script (which will return the same ######). You can use ps aux | grep script to view the number as well.
When you are ready to kill the ./script process, you simply pass the number (e.g. ######) to kill. You can do that directly with:
$ kill $(</tmp/scriptPID)
(or with the other methods listed in my comment)
You can add rm /tmp/scriptPID to remove the pid file after killing the process.
Look things over and let me know if you have any further questions.

How to Parse Values from output in BASH

I'm writing a script that should create a rotating series of debug logs as it runs over a period of time. My current problem is that when I ran it with -vx attached, I can see that it stops during the actual debugging process and doesn't proceed through the loop. This is reflective of how the command would run normally. So I thought to continue the process, I want to run with &.
The problem is that this will become exponentially messier over time (since none of the processes are stopping). So what I'm looking for is a way to parse the PID output of the & command into a variable, and then I will add a kill command at the start of the loop pointed at that variable.
Figuring out how to parse the output of commands will also be useful in the other part of my project, which is to terminate the while loop based on a particular % free in a df -h for a select partition
No parsing needed. The PID of the most recent background process is stored in $!.
command & # run command in background
pid=$! # save pid as $pid
...
kill $pid # kill command

is there any way to know the pid of a launched program?

if I launch a bash script as a child, I can pass its own pid to the parent by using $$.
Is there any way to find the pid of a program that I launch from a script in background
like:
ping x.x.x.x &
what's the pid of that ping ?
(I just hope I expressed my self correctly ... my English is not the best)
PS. I'm looking for a simple and clean solution, I can imagine something like:
ping -t10000 -W10 x.x.x.x &
then
ps ax | grep 'ping -t10000 -W10 x.x.x.x'$
but is too complicated, also even that I used switches to personalize it is not clean, it may catch another processes in the system
The variable $! has the PID of the last background process you started.
Use this: $! right after executing the command whose PID you want. It means, though that you need to use an ampersand (&) after the command, to start it in background. E.g.:
my_command & CMDPID=$!
echo "$CMDPID"

Kill a child process that has detached from the shell

I want to control many different Sinatra apps from a central (Sinatra) app.
The problem I have is no matter which way I exec/spawn/fork the call to start it, I cannot get the pid of the Sinatra server so that I can kill (:int) it?
This is due to my shell exec string, which contains a few other commands first, so I get the pid of the first.
My command string is like
command = source ~/.profile; rbenv #{ver}; some_env=1234 ruby app.rb
So I get the pid of the sh process of the sourcing command.
The question is, how can I get the pid of the ruby command launched above?
I am currently using spawn, but have tried most others as well, but I don't think that is the problem!?
pid = Process.spawn(command)
pid # => 1234
The ruby app itself starts
$ ps aux
1234 sh -c . ~/.profile; shell_script
4567 shell_script
I want to know 4567!?
There's no easy way of getting your '4567', but you should be able to make your process have the same pid as Process.spawn returns.
Try ending your command with an exec rather than a straight call to ruby, i.e.:
source ~/.profile; rbenv #{ver}; export some_env=1234; exec ruby app.rb
you can check whether the process "shell_script" is a child of "sh -c . ~/.profile; shell_script".you can check this through "ps -axgf" command.
if it is a parent then u can use the group id of pid 1234 (get it form the output of ps -axgf) to kill the child with pid 4567 using this command .
kill -9 -1234(assumming 1234 is the group id)

Resources