3

A script for terminating a server on a certain port:

#!/bin/bash

PORT="$1" SIGNAL="$2"

if [ "${SIGNAL}" != "" ]; then SIGNAL=" -${SIGNAL}"; fi

lsof -i:"${PORT}" |
grep -e "localhost:${PORT}" -e TCP -e LISTEN |
tr -s ' ' |
cut -d' ' -f2 |
tee /dev/tty |
xargs --no-run-if-empty kill "$SIGNAL"

Works: killbyport 4242

But if I want to do a kill -9 I'd do: killbyport 4242 9, and that errors:

kill: (-9): No such process

The xargs and kill aren't cooperating – how do I fix it?

(PS: I want to fix this script, rather than change it to something else. It's almost working.)

lonix
  • 1,723
  • Always paste your script into https://shellcheck.net, a syntax checker, or install shellcheck locally. Make using shellcheck part of your development process. – waltinator Mar 13 '22 at 02:26
  • @waltinator Thanks. Note shellcheck gives "No issues detected!" :) – lonix Mar 13 '22 at 02:30
  • You do not need to escape the newline after the pipe character. IMHO it is best to avoid escaping newline when possible. – pabouk - Ukraine stay strong Mar 13 '22 at 16:10
  • @pabouk Interesting, why do you suggest not to escape newlines? – lonix Mar 14 '22 at 02:49
  • Backslash used for line continuation has multiple problems: * You have to be careful that the backslash is not followed by a whitespace (invisible in most editors by default) or any other character. * You cannot add a comment to such a line. --- See for example this answer for Python (almost the same situation as in a shell): https://stackoverflow.com/a/61933/320437 – pabouk - Ukraine stay strong Mar 14 '22 at 08:36

3 Answers3

12

The problem is that you’re explicitly adding a space to SIGNAL:

SIGNAL=" -${SIGNAL}"

and then referencing it in quotes:

kill "$SIGNAL"
Since kill is seeing an argument that doesn’t begin with dash (because it begins with space, and then dash), it isn’t seen as an option, but as an ordinary argument — in this case, a PID.  A quick fix is to not add the space to SIGNAL:
SIGNAL="-${SIGNAL}"

But it doesn’t make sense that this is working when SIGNAL is null.  See But what if …?.  The first example (ignorecase) almost exactly matches your situation.

3

@G-Man's answer led me in the right direction. For completeness, the fix is to use this instead:

xargs --no-run-if-empty kill ${SIGNAL:+"-$SIGNAL"}
lonix
  • 1,723
2

The result of this is to run the command kill " -9" ... which is wrong. Kill will interpret " -9" as a pid instead of "-9" which would be signal 9.

You are being too clever with your quoting.

user10489
  • 6,740
  • isn't it the leading whitespace that's the real problem here, rather than the quoting? – steeldriver Mar 13 '22 at 02:34
  • @steeldriver: It's both.  Adding the space is an error, but, if $2 was a valid non-negative integer, kill $SIGNAL (without quotes) would have worked (but for the wrong reason). – G-Man Says 'Reinstate Monica' Mar 13 '22 at 02:38
  • Without the quotes, the extra space is stripped. With the quotes, the kill works, but doesn't use the specified signal because it thinks it is a pid that it can't find. – user10489 Mar 13 '22 at 02:58
  • I've never been accused of being too clever... thanks! ;) – lonix Mar 13 '22 at 06:05