No such process at killing command after sometime - bash

I want to run an application from bash and kill it after sometime. I found this answer:
xmessage "Hello World" & pidsave=$! sleep 10; kill $pidsave
But this is the result:
[4] 23034
[3] Terminated xmessage "Hello World"
bash: kill: (22985) - No such process
As you see, xmessage did not stopped and it's window remains. Of course this works:
your_command & sleep 20; kill $!
What is wrong in first command? And what is it's prefer in comparison whit second command?

The process xmessage terminal already when you are running the kill command to kill it.
This can be seen here:
[3] Terminated xmessage "Hello World"
so there is no point kill-ing it afterwards.
To answer why the window is still there:
Many processes spawn another process, after that kills itself. This is happening in this case, the process you have spawned by running xmessage from terminal is spawning another one (the one with the window) and exits after that. The child remains running, and becomes an orphan as the parent died (init becomes it's new parent as init inherits all orphans).

Related

Why is nohup required and disown doesn't work by itself?

Consider this snippet as being saved in a file called snippet.sh:
nohup xmessage HI </dev/null &>/dev/null & disown
sleep 3
From the same directory, do xterm -e bash snippet.sh.
After 3 seconds, the xterm should disappear while the xmessage window lingers. All good and well. But what if the nohup is removed from the command in the snippet file? Then the xmessage which disappears along with the xterm. The bash documentation seems to indicate that disown should, by itself, be sufficient to prevent SIGHUP from being sent:
The shell exits by default upon receipt of a SIGHUP. Before exiting, an interactive shell resends
the SIGHUP to all jobs, running or stopped. Stopped jobs are sent SIGCONT to ensure that they
receive the SIGHUP. To prevent the shell from sending the signal to a particular job, it should be
removed from the jobs table with the disown builtin (see SHELL BUILTIN COMMANDS below) or marked to
not receive SIGHUP using disown -h.
So, the question is, why won't the xmessage window linger without nohup?
disown is sufficient to prevent the shell from sending the signal, but it doesn't stop anyone else.
In particular, the shell is the controlling process of the terminal with xmessage in its process group, and POSIX says that on exit:
If the process is a controlling process, the SIGHUP signal shall be sent to each process in the foreground process group of the controlling terminal belonging to the calling process.

Trying to close all child processes when I interrupt my bash script

I have written a bash script to carry out some tests on my system. The tests run in the background and in parallel. The tests can take a long time and sometimes I may wish to abort the tests part way through.
If I Control+C then it aborts the parent script, but leaves the various children running. I wish to make it so that I can hit Control+C or otherwise to quit and then kill all child processes running in the background. I have a bit of code that does the job if I'm running running the background jobs directly from the terminal, but it doesn't work in my script.
I have a minimal working example.
I have tried using trap in combination with pgrep -P $$.
#!/bin/bash
trap 'kill -n 2 $(pgrep -P $$)' 2
sleep 10 &
wait
I was hoping that on hitting control+c (SIGINT) would kill everything that the script started but it actually says:
./breakTest.sh: line 1: kill: (3220) - No such process
This number changes, but doesn't seem to apply to any running processes, so I don't know where it is coming from.
I guess if the contents of the trap command get evaluated where the trap command occurs then it might explain the outcome. The 3220 pid might be for pgrep itself.
I'd appreciate some insight here
Thanks
I have found a solution using pkill. This example also deals with many child processes.
#!/bin/bash
trap 'pkill -P $$' SIGINT SIGTERM
for i in {1..10}; do
sleep 10 &
done
wait
This appears to kill all the child processes elegantly. Though I don't properly understand what the issue was with my original code, apart from sending the correct signal.
in bash whenever you you use & after a command it places that command as a background job ( this background jobs are called job_spec ) which is incremented by one until you exit that terminal session. You can use the jobs command to get the list of the background jobs running. To work with this jobs you have to use the % with the job id. The jobs command also accept other options such as jobs -p to see the proces sids of all jobs , jobs -p %JOB_SPEC to see the process of id of that particular job.
#!/usr/bin/env bash
trap 'kill -9 %1' 2
sleep 10 &
wait
or
#!/usr/bin/env bash
trap 'kill -9 $(jobs -p %1)' 2
sleep 10 &
wait
I implemented something like this few years back, you can take a look at it async bash
You can try something like the following:
pkill -TERM -P <your_parent_id_here>

shell script process termination issue

/bin/sh -version
GNU sh, version 1.14.7(1)
exitfn () {
# Resore signal handling for SIGINT
echo "exiting with trap" >> /tmp/logfile
rm -f /var/run/lockfile.pid # Growl at user,
exit # then exit script.
}
trap 'exitfn; exit' SIGINT SIGQUIT SIGTERM SIGKILL SIGHUP
The above is my function in shell script.
I want to call it in some special conditions...like
when:
"kill -9" fires on pid of this script
"ctrl + z" press while it is running on -x mode
server reboots while script is executing ..
In short, with any kind of interrupt in script, should do some action
eg. rm -f /var/run/lockfile.pid
but my above function is not working properly; it works only for terminal close or "ctrl + c"
Kindly don't suggest to upgrade "bash / sh" version.
SIGKILL cannot be trapped by the trap command, or by any process. It is a guarenteed kill signal, that by it's definition cannot be trapped. Thus upgrading you sh/bash will not work anyway.
You can't trap kill -9 that's the whole point of it, to destroy processes violently that don't respond to other signals (there's a workaround for this, see below).
The server reboot should first deliver a signal to your script which should be caught with what you have.
As to the CTRL-Z, that also gives you a signal, SIGSTOP from memory, so you may want to add that. Though that wouldn't normally be a reason to shut down your process since it may be then put into the background and restarted (with bg).
As to what do do for those situations where your process dies without a catchable signal (like the -9 case), the program should check for that on startup.
By that, I mean lockfile.pid should store the actual PID of the process that created it (by using echo $$ >/var/run/myprog_lockfile.pid for example) and, if you try to start your program, it should check for the existence of that process.
If the process doesn't exist, or it exists but isn't the right one (based on name usually), your new process should delete the pidfile and carry on as if it was never there. If the old process both exists and is the right one, your new process should log a message and exit.

Getting pid of a background gnome-terminal process

I can easily start a background process, find its pid and search it in the list of running processes.
$gedit &
$PID=$!
$ps -e | grep $PID
This works for me. But if I start gnome-terminal as the background process
$gnome-terminal &
$PID=$!
$ps -e | grep $PID
Then, it is not found in the list of all running process.
Am I missing something here?
If you use the "--disable-factory" option to gnome-terminal it's possible to use gnome-terminal in the way you desire. By default it attempts to use an already active terminal, so this would allow you to grab the pid of the one you launch. The following script opens a window for 5 seconds, then kills it:
#!/bin/bash
echo "opening a new terminal"
gnome-terminal --disable-factory &
pid=$!
echo "sleeping"
sleep 5;
echo "closing gnome-terminal"
kill -SIGHUP $pid
This appears to be because the gnome-terminal process you start starts a process itself and then exits. So the PID you capture is the pid of the "stub" process which starts up and then forks the real terminal. It does this so it can be completely detached from the calling terminal.
Unfortunately I do not know of any way of capturing the pid of the "granchild" gnome-terminal process which is the one left running. If you do a ps you will see the gnome-terminal "grandchild" process running with a parent pid of 1.
(This is just a footnote) As #Sodved said, gnome-terminal starts a process itself and then exits, there is no way to get the grandchild pid. (See also APUE Chapter 7 why a child process won't re-attach to the grandparent process when its parent process was terminated. )
I found that gnome-terminal instantiates only once, so here is just a short script for your specific task:
GNOME_TERMINAL_PID=`pidof gnome-terminal`
If you don't have pidof:
GNOME_TERMINAL_PID=`grep Name: */status | grep gnome-terminal | cut -d/ -f1`

How to run two processes as though they were one in bash?

I've got two commands foo and bar.
foo runs for a long time without stdin or stdout/stderr activity. bar is a client of foo and runs with stdout/stderr but no stdin activity.
I'd like to run them from one shell, being able to kill both with ctrl-c, and to see the output from bar as it occurs.
i.e. something like this sequence
foo &
bar
kill -9
but without having to manually do the kill - instead it just happens on ctrl-c
is there a way of scripting this?
thanks
Don't use kill -9.
You want to trap on EXIT, not on INT.
trap 'kill $fooPid $barPid' EXIT
foo & fooPid=$!
bar & barPid=$!
wait
This solution will always make sure to terminate foo and bar, whatever the reason for it exiting (excluding it being SIGKILL'ed).
If you want to avoid keeping PIDs (which has some race condition issues) you can do this instead:
trap 'kill $(jobs -p)' EXIT
foo &
bar &
wait
That's a better (and cleaner!) solution if your script has no other jobs.
Ps:
These solutions mean foo and bar can write to your terminal (your script's stdout), but neither can read from stdin. If you need either foo or bar to read from stdin, the solution becomes a bit more complex.
You can set up a bash script to run the programs and use trap to capture the CTRL-C. Then, in the function called by trap, just kill off the programs.
It's been a while since I did this but I think the following illustrates it.
#!/bin/bash
xx() {
kill -9 $pid1
kill -9 $pid2
echo bye
}
trap 'xx' SIGINT
sleep 1000 &
pid1=$!
sleep 2000 &
pid2=$!
sleep 3600
Just run this script and CTRL-C it, you'll find that it kills off the two sleep processes.

Resources