I have a process I spawn with a Cygwin shell script, and I am unable to kill it with the kill
command. Even with the Cygwin kill with the -f
option, I get this message:
kill: couldn't open pid 1234
I would like to try to kill it with PsKill, but I cannot find a way to convert the Cygwin PID
to a Windows PID
t开发者_运维百科hat PsKill
will understand. How can I do that?
Have you tried running the cygwin kill instead of the bash builtin? If it is a Windows PID then type:
/bin/kill -f 1234
or if it is a Cygwin PID then type:
/bin/kill -9 1234
As far as I know there is no API to Cygwin that you could call to translate a Cygwin PID to a Windows PID. However, you could parse the output of ps -W
to do the conversion. Or, if you really, really don't want to do that, then have a look at the source code for the Cygwin ps
command, and see where they get the pids from. The Cygwin ps source code is here.. You could write a small utility in C to take the Cygwin pid and give you a Windows pid.
ps -W
will show the Windows PID in addition to the Cygwin PID.
Or, you can do it programmatically like this:
#include <sys/cygwin.h>
winpid = cygwin_internal(CW_CYGWIN_PID_TO_WINPID, cygpid);
The proc file system has the windows PID for cygwin PID $pid in /proc/$pid/winpid
.
> notepad&
[1] 11716
> taskkill /f /pid $(</proc/$!/winpid)
ERFOLGREICH: Der Prozess mit PID 11976 wurde beendet.
[1]+ Exit 1 notepad
This works in sh shell:
./${Z_BIN} &
Z_PID=$!
Z_PIDW=`ps -p ${Z_PID} | awk -e '/^[[:space:]]+[[:digit:]+]/{print $4}'`
Z_BIN contains your program to execute. Z_PID will contain cygwin pid and Z_PIDW will contain windows pid for the same program. You can save Z_PIDW in to a pid file and use it later for killing or any other purpose.
The best way to kill running Bash scripts from Cygwin is using the Sysinternals tool PsKill64.exe
. The reason is that Cygwin's ps
also give PID's that are different from WINPID
.
In addition, pskill
also has the -t
flag that kills the entire process tree, which means any other threads/sub-processes that your script may have started. Of course kill -9 <PID>
also works, but it doesn't kill descendants already started by the script.
# cat sleeper.sh
ZID=$$
WINPID=$(cat /proc/${ZID}/winpid)
echo "WINPID: ${WINPID}"
sleep 10
Now run with:
$ ./sleeper.sh &
[1] 8132
WINPID: 8132
$ ps
PID PPID PGID WINPID TTY UID STIME COMMAND
#5280 1 5280 5280 ? 1001 14:21:40 /usr/bin/mintty
#7496 5684 7496 3836 pty0 1001 20:48:12 /usr/bin/ps
#5684 5280 5684 6052 pty0 1001 14:21:40 /usr/bin/bash
5948 8132 8132 3900 pty0 1001 20:48:11 /usr/bin/sleep
8132 5684 8132 8132 pty0 1001 20:48:11 /usr/bin/bash
As you see, this starts two processes, the main bash
script and the sleep thread. So if you kill -1 8132
the sleep thread will continue running, but if you use pskill64 -t 8132
, you will kill all its descendants too. Analogous to the linux killall
command.
I searched the web to see if anyone had a function or script to convert cygwin PIDs to Microsoft PIDs. I found none; so I made my own. I am putting it up here for safe keeping (when I do not have access to my life-time of scripts that I have programmed). This is becoming a frequent solution for me out in the wild.
#!/usr/bin/env bash
# Convert a cygwin PID to a Microsoft PID using bash and perl
ps -W | perl -e '
my ($line, $arg,$errno,@columns);
$errno=1;
while($line = ){
chomp($line);
$line=~s/^\s+//g;s/\s+$//g;
for $arg (@ARGV){
if ($line=~/^${arg}/){
$errno=0;
@columns=split(/\s+/,$line);
print STDOUT $columns[3];
last;
}
}
}
exit($errno);
' "${@}"
The kill using `taskkill` and/or `kill` cygwin terminal.
<pre><code>
taskkill /F /IM ${m1crosoft_pid_goes_here}
kill -9 ${cygwin_pid_goes_here_tmp}
Use file descriptor when you can and use instead of that pipe.
精彩评论