killでプロセスIDかプロセス名を補完する

[zsh] killコマンドでpidやコマンド名の補完 〜Just another Ruby porter,
に触発されてbashで同じようなことをしてみる。

$ kill 224<TAB>
22421 hirose31 pts/15   00:00:06 emacs
22491 hirose31 tty1     00:00:01 kterm
22493 hirose31 pts/16   00:00:00 /bin/bash

$ kill su<TAB>
su -                        21928 root     pts/14   00:00:00
sudo xconsole -fg red -bg g 21653 root     tty1     00:00:00
supervise log                2267 root     ?        00:00:00
supervise log                2269 root     ?        00:00:00
supervise qmail-send         2268 root     ?        00:00:00
supervise smtpd              2266 root     ?        00:00:00

コードはこんな感じ。元はbash-completionからパクりました。

## kill
_signals() {
    local i

    # standard signal completion is rather braindead, so we need
    # to hack around to get what we want here, which is to
    # complete on a dash, followed by the signal name minus
    # the SIG prefix
    COMPREPLY=( $( compgen -A signal SIG${cur#-} ))
    for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
        COMPREPLY[i]=-${COMPREPLY[i]#SIG}
    done
}

_pids() {
    case $cur in
        [a-zA-Z]*)
            c=$( compgen -W '$( ps axo cmd | sed 1d )' -- $cur | wc -l)
            if [ $c -eq 1 ]; then
                # compgenを使ってないので不安…
                COMPREPLY=( $(ps axo pid,cmd | awk "\$2 ~ /^${cur}/{print \$1}") )
            else
                IFS='
' COMPREPLY=( $( compgen -W '$( ps axo cmd,pid,user,tty,time | sed 1d | cut -c 1-76 )' -- $cur) )
            fi
            ;;
        *)
            c=$( compgen -W '$( ps axo pid | sed 1d )' -- $cur | wc -l)
            if [ $c -eq 1 ]; then
                COMPREPLY=( $( compgen -W '$( ps axo pid | sed 1d )' -- $cur) )
            else
                IFS='
' COMPREPLY=( $( compgen -W '$( ps axo pid,user,tty,time,cmd | sed 1d | cut -c 1-76 )' -- $cur) )
            fi
            ;;
    esac
}

_kill() {
    local cur

    COMPREPLY=()
    cur=${COMP_WORDS[COMP_CWORD]}

    if [ $COMP_CWORD -eq 1 ] && [[ "$cur" == -* ]]; then
        # return list of available signals
        _signals
    else
        # return list of available PIDs
        _pids
    fi
}
complete -F _kill kill