#!/usr/bin/env perl ################### $0="jobsel"; sub heply { $pos = tell DATA; print STDERR ; seek DATA,$pos,0 } exit heply if $ARGV[0] eq '--help'; use Term::ReadKey; ReadMode 4; sub bye { print STDOUT "export JOBSEL_DISPLAY_MODE=$dispmode"; exit ReadMode 0 } sub getkey { while(not defined ($k = ReadKey(-1))){} return $k } $SIG{INT}=$SIG{STOP}=$SIG{STOP}=$SIG{TSTP}=$SIG{QUIT}='bye'; $dispmode = $ENV{JOBSEL_DISPLAY_MODE} eq "x" ? "x" : "c"; while(1){ @o=@x=(); for(split/[\r\n]+/,$ARGV[0]){ ($j,$p)=/(\d+)\]\S?\s+(\d+)/; if ( open(P,"/proc/$p/stat") and ($c,$s)=(

=~/\s\((.+?)\)\s+(\S+)/) ) { close P; push @o,[$j,$c,$p,$s]; # job number, command, pid, state s/(\S+\s+){3}//; push @x,sprintf "[%d] %5d %s",$j,$p,$_; } } bye unless @o; $in=$#o if $in>$#o; $pos = tell STDERR; print STDERR "\033[s\033[1;0H"; if($dispmode eq "x") { for(0..$#o) { printf STDERR "%s%s\033[m\n",($_==$in?"\033[44;1;36m":"\033[1;36m"),$x[$_]; } } else { print STDERR "\033[1;36mjobs: "; for(0..$#o) { printf STDERR "%s[%%%s %s(%s) %s]\033[m ",($_==$in?"\033[44;1;36m":"\033[1;36m"),@{$o[$_]}; } } print STDERR "\033[u"; $k=getkey; if($k eq chr(27)) { $k=getkey; if($k eq '[') { $k=getkey; if($k =~ /[DA]/) { # arrow left/up $in-- if $in > 0 } elsif($k =~ /[CB]/) { # arrow right/down $in++ if $in < $#o } elsif($k =~ /[H5]/) { # home/pg up $in=0 } elsif($k =~ /[F6]/) { # end/pg down $in=$#o } elsif($k eq chr(27)) { bye } } elsif($k eq chr(27)) { bye } } elsif($k =~ /[ts ]/i) { kill ${$o[$in]}[3] eq 'T' ? 18 : 20, ${$o[$in]}[2]; # CONT,TSTP } elsif($k =~ /k/i) { kill 9, ${$o[$in]}[2]; # KILL } elsif($k =~ /h/i) { kill 1, ${$o[$in]}[2]; # HUP } elsif($k =~ /i/i) { kill 2, ${$o[$in]}[2]; # INT } elsif($k =~ /d/i) { $/=undef; print STDERR "Commandline:\t"; open A,"/proc/".${$o[$in]}[2]."/cmdline"; print STDERR join(" ",split/\x0/,)."\n"; close A; print STDERR "Directory:\t"; print STDERR readlink "/proc/".${$o[$in]}[2]."/cwd","\n"; $/="\n"; open A,"/proc/".${$o[$in]}[2]."/status"; /^(ppid|uid|gid):/i and print STDERR $_ while; close A; } elsif($k =~ /[xc]/i) { $dispmode=lc $k; } elsif($k eq '?') { heply } elsif($k =~ /[\r\n]/) { ReadMode 0; print STDOUT "export JOBSEL_DISPLAY_MODE=$dispmode; fg ".$o[$in][0]; exit 0; } elsif($k =~ /q/i) { bye } # clear screen region print STDERR "\033[s\033[1;0H"; if($dispmode eq "x") { print STDERR " " x ($ARGV[1] || `tput cols`), "\n" for @x } else { print STDERR " " x (-$pos+tell STDERR) } print STDERR "\033[u"; } __END__ NAME jobsel SYNOPSIS $ eval $(jobsel "$(jobs -l)" $COLUMNS) DESCRIPTION Improved job control frontend for bash KEYS Left,Right Select item Enter Switch to job in forground H Hangup selected process I Interrupt process S,T,Space Suspend, Resume job K Kill process D Process' details X,C Expanded, collapsed display mode Q Dismiss jobsel ? Help HINTS Define an alias! alias j='eval $(jobsel "$(jobs -l)" $COLUMNS)' Bind a function key for it! bind -x '"\204"':"eval \$(jobsel \"\$(jobs -l)\" \$COLUMNS)" bind '"\ej"':"\"\204\"" # ESC-J Where: 204 is an arbitrary free keyscan code