Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?

bash alias suggest-ation

by khkramer (Scribe)
on Jan 04, 2002 at 21:04 UTC ( #136304=CUFP: print w/replies, xml ) Need Help??

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; /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/"; 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; \ /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\ END exit ( 0 ); }
Just starting to come out of my shell,

Replies are listed 'Best First'.
Re: bash alias suggest-ation
by archen (Pilgrim) on Jan 05, 2002 at 02:51 UTC
    okay, newbie level question :)

    why are you printing on STDERR?

      Not a newbie-level question at all...

      The tricky thing about this script is getting it to interact properly with the system environment. There are a couple of problems: 1) you can't get at the history list from inside the script because "history" is a shell built-in and the ".bash_history" file isn't kept up to date, and 2) you can't create aliases from inside the script because there's no way to export aliases out to the calling context.

      The first problem is addressed by taking the history list as input. (But not simply as STDIN, because then you couldn't prompt the user for input.)

      The second problem is solved by using the script in a "command substitution" context -- surrounded by backticks or $(). The only thing that gets printed on STDOUT is the name of the file to which the script writes the "alias foo='bar'" commands. That filename is what the bash "source" builtin sees. So, you don't have access to STDOUT for the interface (it doesn't even show up on the terminal): you have to use STDERR instead. Definitely a kludgy hack, but it works fine for this purpose.

Re: bash alias suggest-ation
by dmmiller2k (Chaplain) on Jan 05, 2002 at 03:08 UTC

    Nice work!

    "Just starting to come out of my shell ..."

    Keep it coming!


    You can give a man a fish and feed him for a day ...
    Or, you can
    teach him to fish and feed him for a lifetime
Re: bash alias suggest-ation
by venerable_bede (Initiate) on Jan 05, 2002 at 00:34 UTC
    that's a good idea!

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: CUFP [id://136304]
Approved by root
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (9)
As of 2017-02-27 15:00 GMT
Find Nodes?
    Voting Booth?
    Before electricity was invented, what was the Electric Eel called?

    Results (388 votes). Check out past polls.