5

When I try to execute pkill on a remote host in combination with another command, it always returns 255, even though both the commands were successful.

Examples

  1. ssh <remoteHost> 'pkill -f xyz' # returns 0 (rightly so when xyz is a process)
    
  2. ssh <remoteHost> 'source /etc/profile' # returns 0 (rightly so)
    

But when I run the combination command:

  1. ssh <remoteHost> 'source /etc/profile; pkill -f xyz' # returns 255 - why?
    

There's something about "pkill" in combination with another command because the following returns zero even though it's a combination:

  1. ssh <remoteHost> 'source /etc/profile; ls' # returns 0
    

Assume that xyz is running at all times when we try to kill it.

I do not understand this behavior. Why does it return 255 in case 3?

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
  • It this reproducible? Return code 255 with SSH means an error occurred in SSH and is not the error return by the command run through SSH – damienfrancois Nov 07 '16 at 20:26
  • Yes, it is reproducible all the time. If error occured in SSH, then the kill should've failed. But the actual result is that the process DOES get killed. However, the return code is 255. – Mohsin Khan Nov 07 '16 at 21:05

1 Answers1

8

The documentation for the pkill -f option says:

-f
The pattern is normally only matched against the process name. When -f is set, the full command line is used.

So pkill -f xyz will kill any process with "xyz" anywhere on its command line.

When you run ssh <remoteHost> 'source /etc/profile; pkill -f xyz', the remote ssh server will run the equivalent of this on your behalf:

$SHELL -c 'source /etc/profile; pkill -f xyz'

The resulting shell instance is a process with "xyz" in its command line. My guess is that pkill is killing it, and ssh is reporting the killed session as exit code 255, like this:

$ ssh localhost 'kill $$'
$ echo $?
255

It doesn't happen when you just run ssh <remoteHost> 'pkill -f xyz', because some shells like bash will optimize for this case. Instead of running pkill as a subprocess, the shell instance will replace itself with the pkill process. So by the time pkill runs, the shell process with "xyz" on its command line is gone.

You can probably work around this by running pkill like this:

ssh <remoteHost> 'source /etc/profile; exec pkill -f xyz'

If that doesn't work, you can specify the pkill pattern in such a way that it doesn't match the pattern itself. For example:

ssh <remoteHost> 'source /etc/profile; exec pkill -f "[x]yz"'

The pattern [x]yz matches the text "xyz", so pkill will kill processes where the text "xyz" appears. But the pattern doesn't match itself, so pkill won't kill processes where the pattern appears.

Kenster
  • 23,465
  • 21
  • 80
  • 106
  • Thanks for the detailed explanation. It works with exec! That answer resolves my issue. I really appreciate it. – Mohsin Khan Nov 08 '16 at 02:09
  • Your answer is absolutely correct. I am just nitpicking. `source` is a builtin command which requires, like you stated, `bash -c`. `pkill` on the other hand is an external command which can be executed directly. – alvits Nov 08 '16 at 04:00