Skip to content

Instantly share code, notes, and snippets.

@chrisfesler
Created November 4, 2025 17:33
Show Gist options
  • Select an option

  • Save chrisfesler/c59e1e5670e9db326c7bd2be102a42a6 to your computer and use it in GitHub Desktop.

Select an option

Save chrisfesler/c59e1e5670e9db326c7bd2be102a42a6 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
require 'open3'
SIGNALS = [
[15, 3],
[2, 3],
[1, 4],
[9, 0]
]
def i?(arg)
arg.to_i != 0
end
def capture_lines(*command)
output, status = Open3.capture2(*command)
return [] unless status.success?
output.lines
end
def running?(pid)
capture_lines('ps', '-p', pid.to_s).length >= 2
end
def go_ahead?
response = $stdin.gets
return false unless response
%w(y yes yas).include? response.strip.downcase
end
def kill(pid, code)
Process.kill(code.to_i, pid.to_i)
rescue Errno::ESRCH, Errno::EPERM
false
end
def murder_pid(pid)
SIGNALS.each do |signal|
break unless running? pid
code, wait = signal
kill(pid, code)
sleep 0.5
sleep(wait) if running? pid
end
end
def murder_names(name)
regex = /\b#{Regexp.escape(name)}\b/i
loop do
should_loop = false
running = capture_lines('ps', '-eo', 'pid=,command=')
running.each do |line|
pid, fullname = line.strip.split(nil, 2)
next unless pid && fullname
next unless regex.match?(fullname)
next if Process.pid == pid.to_i
print "murder #{fullname.chomp} (pid #{pid})? "
if go_ahead?
murder_pid(pid)
should_loop = true
break
end
end
break unless should_loop
end
end
def murder_port(arg)
loop do
should_loop = false
lsofs = capture_lines('lsof', '-i', arg.to_s)
lsofs.drop(1).each do |line|
pid = line.split(nil, 3)[1]
next unless pid
fullname = capture_lines('ps', '-p', pid.to_s, '-o', 'command=').first
fullname = fullname ? fullname.chomp : '<unknown>'
print "murder #{fullname} (pid #{pid})? "
if go_ahead?
murder_pid(pid)
should_loop = true
break
end
end
break unless should_loop
end
end
def murder(arg)
is_pid = i?(arg)
is_port = arg[0] == ':' && i?(arg.slice(1, arg.size))
if is_pid
murder_pid arg
elsif is_port
murder_port arg
else
murder_names arg
end
end
if ARGV.size < 1
puts 'usage:'
puts 'murder 123 # kill by pid'
puts 'murder ruby # kill by process name'
puts 'murder :3000 # kill by port'
exit 1
else
ARGV.each { |arg| murder(arg) }
end
@chrisfesler
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment