12

The script in question terminates the latest process on my localhost port 8080.

#!/bin/bash
x=$(lsof -i:8080 | tail -1 | awk '{print $2}')
kill -9 $x

It didn't work, if the script was named 'killl' (get it? Kill Latest?). It gave me a prompt for cmdsubst> Renaming the script to 'asdf', everything works. Is there an explanation for this behaviour? I'm using MacOS El Capitán.

  • 5
    Do you have another function, alias, utility or other command called killl? – Kusalananda Oct 31 '17 at 9:34
  • 9
    Don't make the names ambiguous. killl can be misinterpreted as wrongly spelled kill. It's better to be explicit and more descriptive: kill_latest or kill_last. – cezar Oct 31 '17 at 9:43
  • 6
    What is the output of type killl in the shell where you tried to start it? – Hauke Laging Oct 31 '17 at 10:23
27

cmdsubst> is the secondary prompt printed by the zsh shell when it's waiting for the end of a command substitution being entered.

If you get that prompt after just entering killl<Return>, then the only reasonable explanation is that you have an alias (which is some form of string macro expansion) for killl that expands to something that contains an unterminated $(...) command substitution, like:

$ alias 'killl=echo $(lsof -ti'
$ killl :22
cmdsubst>

Where zsh is asking you to close that $(...) command substitution.

A few more notes:

  • the output of lsof is sorted by pid. pid numbers are wrapped, a larger pid is not a guarantee that the process was started later.
  • -i:8080 will report TCP or UDP sockets that have the 8080 port as the source or destination port, whether it's a listening, accepting or connecting socket.
  • If you want to get the pid only, you can use the -t option of lsof: lsof -ti:8080 | tail -n2
  • kill -9 is kill -s KILL, which sends a signal that the application cannot act upon to exit gracefully. It should only be used as a last resort.

To kill the most recently started process that has a socket bound (either end) on port 8080, you could do:

#! /bin/sh -
unset IFS
pids=$(lsof -ti:8080) &&
  LC_ALL=C ps -o pid=,lstart= -p $pids |
  LC_ALL=C sort -k6,6n -k4,4M -k3,3n -k5,5 -k1,1n |
  awk 'END{system("kill " $1)}'

(assumes GNU sort (as found on macOS) and a ps implementation that supports the lstart column (like macOS' and procps-ng's, though the code would have to be updated for procps-ng where the month and day fields are swapped)).

1

It gave me a prompt for cmdsubst>

Because when you typed the command you did not type

killl
you typed

killl $(
or similar. This was nothing to do with the name of the script, or even that it was a script in the first place. You could have achieved the same effect with a wholly nonexistent command:

Zeick $(
The shell's parser was expecting more input to complete the only partly complete command. Your thinking about the script name is a complete red herring.

  • 6
    That's a pretty big assumption to say he typed killl $( for some reason, and very unlikely that he did so. Stéphane Chazelas' answer is more likely the case. – Herohtar Oct 31 '17 at 14:59
  • 1
    If it is indeed due to a typo, then ` is more likely than $(. – Emil Jeřábek Oct 31 '17 at 15:50
  • 2
    No, Emil Jeřábek; ` is not likely at all since it does not give the same prompt. Try it. No, Herhtar; it's not an assumption when typing that or similar is the way to get that prompt. It is a deduction. – JdeBP Oct 31 '17 at 16:20
  • 1
    You assert that OP "did not type killl," when as Stéphane Chazelas explains, it is entirely possible that OP did indeed type killl. Therefore, I have downvoted your answer as wrong. – Kevin Nov 1 '17 at 5:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.