That's because gnome-terminal
is "clever". When you fire up gnome-terminal
, it will determine if another instance of gnome-terminal
is already running.
- If no, it creates a new
gnome-terminal
process and spawns a window.
- If yes, it will simply cause that existing
gnome-terminal
process to spawn a new window.
Therefore, all gnome-terminal
windows run as a single process, with a single PID.
You can easily check this by opening up several gnome-terminal
windows, then get their PIDs by issuing xprop _NET_WM_PID
somewhere and click inside them. You will see the PID is the same for all windows.
So what happens in your script?
You're capturing the PIDs of the gnome-terminal
instances you launch alright, but the problem is, those PIDs exist only for the fraction of a second. These processes only cause the existing gnome-terminal
process to spawn a new window, then terminate.
So if you already have an active gnome-terminal
process when executing your script (which I assume), the PIDs you collect don't exist anymore when you try to kill them. If you don't (say, you execute that script from an xterm
or some other terminal emulator), the first PID you collect will indeed be "correct". The following PIDs you collect will be "incorrect". Once you enter your killing loop, the first iteration would kill all gnome-terminal
windows, and the following ones would output errors, because those PIDs don't exist anymore.
So, how to solve this?
Well, off the bat I can think of two ways.
If you don't insist on using gnome-terminal
, use some other terminal emulator instead which doesn't behave in this way. xterm
for example spawns a separate process for each window. If you use xterm
rather than gnome-terminal
in your script, it should work. Easy & clean.
If you do insist on using gnome-terminal
, the way to kill a specific gnome-terminal
window would be to kill the process that's running inside that specific window. As soon as you terminate that process, that window will close. But since you are using that -e
option, this process will be netcat $ipaddress $port
first, then afterwards bash
, and it is hard to get the PIDs. You can't easily collect them as you are currently doing with $!
. You could try something like killall netcat
or killall bash
, but clearly that will also terminate all other netcat
or bash
instances, which you probably don't want. You could possibly grep
over some cleverly designed ps
call to try and find the exact PIDs you want to kill, but that's shaky and error-prone. Honestly, I'd just go for solution 1.
Two minor comments on your script:
Line 10: It should be port=0
, not $port=0
.
Line 13: It should be processarray+=("$!")
, not processarray+= ("$!")
.
Hope that helps.
Edit: Oh, I just found the --disable-factory
option for gnome-terminal
, which causes it to not re-use existing processes. Here's your fixed script:
#!/bin/bash
ipaddress=$1
port=$2
processarray=()
echo "netcat command set to ip: $ipaddress and port: $port"
if [ -z "$ipaddress" ]; then
echo "No ip address entered"
fi
if [ -z "$port" ]; then
echo "No port entered default set to 0"
port=0
fi
for i in {0..9}; do
gnome-terminal --disable-factory -e "bash -c \"netcat $ipaddress $port; exec bash\"" & processarray+=("$!")
done
sleep 10;
for i in "${processarray[@]}"; do
kill "$i"
done
kill
can accept multiple arguments. No need for the loop there. – muru Sep 13 '14 at 12:45