Skip to content

Instantly share code, notes, and snippets.

@sravioli
Last active December 13, 2024 11:33
Show Gist options
  • Save sravioli/9783d22867c36d3f05d1cdee842e8963 to your computer and use it in GitHub Desktop.
Save sravioli/9783d22867c36d3f05d1cdee842e8963 to your computer and use it in GitHub Desktop.
Interactive interface to search for and kill processes using fzf.
#!/usr/bin/env bash
#
# Interactive interface to search for and kill processes using fzf.
# Supports both regular and forced process termination and dynamically updates
# the process list.
#
# Usage: ./fzf-kill.sh [REFRESH_INTERVAL]
# REFRESH_INTERVAL: Optional; time in seconds to refresh the process list (default: 1.2 seconds).
#
# Dependencies: fzf, procs (ps if not found), sed, awk, curl
# Port for FZF to listen for interactions.
declare -ir FZF_KILL_PORT=6266
# Ensures the FZF process monitor is stopped by setting a flag.
# Globals:
# None
# Arguments:
# None
# Outputs:
# Writes 'false' to /tmp/fzf-kill-running.
function __fzf::kill::ensure-stopped() { echo false >/tmp/fzf-kill-running; }
# Extracts the PID from a process information string.
# Globals:
# None
# Arguments:
# $1 - A line of process information.
# Outputs:
# Prints the extracted PID.
function __fzf::kill::get-pid() { echo "$1" | sed --expression='s/^[ \t]*//' | awk '{ print $1 }'; }
# Retrieves the name of a process based on its PID.
# Globals:
# None
# Arguments:
# $1 - The PID of the process.
# Outputs:
# Prints the process name.
function __fzf::kill::get-pname() { ps -oargs= --pid "$1"; }
# Checks if a process with a given PID is running.
# Globals:
# None
# Arguments:
# $1 - The PID of the process.
# Outputs:
# Prints the PID if the process is running; otherwise, errors.
function __fzf::kill::check-process() { ps -opid= --pid "$1"; }
# Interactively asks the user whether to kill a process, with optional force.
# Globals:
# None
# Arguments:
# $1 - The process information string.
# $2 - Optional; "true" to force kill (default: "false").
# Outputs:
# Executes `kill` or `kill -9` based on user input.
function __fzf::kill::ask() {
local pid answer force pname
pid="$(__fzf::kill::get-pid "$1")"
pname="$(__fzf::kill::get-pname "${pid}")"
force="${2:-false}"
answer="$(
echo -e 'no\nyes' |
fzf --bind=$'start:transform-border-label:
if [[ '"${force}"' = false ]]; then
echo "$ kill '"${pid}"'? ('"${pname}"')"
else
echo "$ kill -9 '"${pid}"'? ('"${pname}"')"
fi' \
--prompt='Choose❭ ' --preview-window='hidden' \
--preview="echo \"{ pid: ${pid}, force: ${force}, pname: ${pname} }\"" \
--preview-label=' Debug info' --color='label:red,preview-label:yellow'
)"
case "${answer}" in
yes)
if __fzf::kill::check-process "${pid}"; then
if [[ "${force}" = true ]]; then
kill -9 "${pid}"
else
kill "${pid}"
fi
fi
;;
no | *) return 1 ;;
esac
}
export -f "__fzf::kill::ask"
export -f "__fzf::kill::get-pid"
export -f "__fzf::kill::get-pname"
export -f "__fzf::kill::check-process"
export -f "__fzf::kill::ensure-stopped"
# Main function to interactively search and kill processes using FZF.
# Globals:
# FZF_KILL_PORT
# Arguments:
# $1 - Optional; refresh interval for process list (default: 1.2 seconds).
# Outputs:
# Executes `kill` or `kill -9` based on user actions.
function __fzf::kill() {
local fzf_flags
if command -v procs >/dev/null; then
cmd="/usr/bin/procs"
flags=(--color=always --theme=auto --pager=disable --use-config=default "${USER}" --sortd=CPU)
fzf_flags=(--header-lines=2)
else
cmd="/usr/bin/ps"
flags=(-u"${USER}" -o"pid,user,tty,%cpu,%mem,args" --sort=pcpu)
fzf_flags=(--header-lines=1)
fi
"${cmd}" "${flags[@]}" | fzf "${fzf_flags[@]}" \
--listen="${FZF_KILL_PORT}" --height=100% --prompt='Search❭ ' --border-label='󰓥 Kill process' \
--bind='ctrl-g:last,alt-g:first' --header='<M-k> kill / <M-f>: kill -9' \
--preview-window=$'hidden,bottom,1' --preview-label=' Debug info' \
--preview=$'echo "__fzf::kill::get-pid -> $(__fzf::kill::get-pid {})"' \
--color='label:red,preview-label:yellow' \
--bind=$'alt-k:execute(__fzf::kill::ask {})' \
--bind=$'enter:execute(__fzf::kill::ask {})' \
--bind=$'alt-f:execute(__fzf::kill::ask {} true)' \
--bind=$'focus:transform-header(
echo "<M-k> $ kill "$(__fzf::kill::get-pid {})""
echo "<M-f> $ kill -9 "$(__fzf::kill::get-pid {})"")' \
--bind=$'start:execute-silent(
echo true >/tmp/fzf-kill-running
while "$(cat /tmp/fzf-kill-running)"; do
curl --silent --request POST "localhost:'"${FZF_KILL_PORT}"'" --data "reload('"${cmd} ${flags[*]}"')" &&
sleep '"${1:-1.2}"'
done &)'
__fzf::kill::ensure-stopped
}
__fzf::kill "$1"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment