Bash provides roughly 23^3 shortcuts and expansions for searching,
editing, and making use of the command
history. (Ob-bashmonks-question: 'what's your favorite ReadLine Key
Binding?' ... 'Ooh, ooh: C-r' ... 'Heck no, you cretin, real monks
only use M-p' ... etc.)
But still, sometimes you need to throw in some Perl. Accordingly, here
is a dollop of code that searches through a history list, extracts
commands that have been repeated some multiple number of times, and
prompts you for aliases to define for those commands.
In typical usage:
source `history | tail -n 400 > /tmp/hist; dynamic-aliases.pl /tmp/his
+t
But, of course, you don't really want to type all that. So cut and
paste, run it a few times (four, unless you change the defaults in the
code or on the command line) and you'll be prompted for an appropriate
alias. (Note, depending on your environment variable settings, a
command run multiple times in a row may only create one entry in your
history list. Be warned. And check out the information on HISTCONTROL
and friends in the bash man page.)
#!/usr/bin/perl -w
use strict;
$|++;
use Getopt::Long;
## -- DEFAULTS --
my $aliases_file = "/tmp/bash_perl_aliases.sh";
my $hist_size = 400;
my $repeats = 4;
my $min_length = 4;
my $help;
## -- -------- --
GetOptions ( 'repeats=i' => \$repeats,
'min_length=i' => \$min_length,
'help' => \$help );
usage() if $help;
my @lines = map { m/\d+\s(.*)$/; $1 || ''; } <>;
my %seen;
my @multiples = sort grep {
++$seen{$_} == $repeats and
length >= $min_length
} map { /^\s*(.+?)\s*$/ } @lines;
if ( @multiples ) {
# print numbered "preview" list
print STDERR
'found ' . @multiples . ' repeat' . (@multiples == 1 ? '' : 's') .
+ "\n";
my $counter = 1;
foreach ( @multiples ) { print STDERR sprintf "%3d: %s\n", $counter+
++, $_; }
# prompt for possible alias-ification and write to aliases file
open ( ALIASES, ">$aliases_file" ) || die "couldn't open outfile: $!
+\n";
prompt ( @multiples );
close ( ALIASES );
print "$aliases_file";
}
print STDERR "\n";
exit ( 0 );
## ------ ##
sub prompt {
foreach my $command ( @_ ) {
print STDERR "$command: ";
my $alias = <>;
last if ! defined $alias; # ctrl-d
chop $alias;
print ALIASES "alias $alias='$command'\n" if $alias;
}
}
sub usage {
print STDERR <<END;
source `history | tail -n 400 > /tmp/hist; \
dynamic-aliases.pl /tmp/hist [ --repeats <repeats> \ ]
[ --min_length <length> \ ]
[ --help ]`
This program munges a history list looking for command lines that
are at least <length> characters long and have been repeated at
least <repeats> times. If it finds any command lines fitting the
criteria, it prompts the user for a (presumably shorter) string to
install as a bash alias for that command. To skip a command line,
the user may simply hit the new-line key.
Default values:
--repeats $repeats
--min_length $min_length
(kwindla\@xymbollab.com)
END
exit ( 0 );
}
Just starting to come out of my shell,
Kwindla