Script de shell que imprime os diretórios mais visitados

5

Existe uma maneira de escrever um script bash com as seguintes funcionalidades?

  1. Ser iniciado quando eu pressionar uma tecla ou combinação de teclas. (requisito não tão importante)
  2. Identifique os 7 diretórios mais visitados nas últimas 3 horas.
  3. Ofereça-me a lista desses 7 diretórios para que eu possa percorrê-los com a aba e a tecla shift (para trás). Em seguida, pressione enter significaria cd para o diretório selecionado.

obrigado

    
por xralf 14.04.2011 / 08:55

2 respostas

7

Adicione o seguinte ao seu arquivo ~/.bashrc :

#### cd history mechanism ##############################################

export CDHISTFILE=~/.cdhistory
if [ -e "$CDHISTFILE" ]
then
    cdht='mktemp'
    tail -500 "$CDHISTFILE" > $cdht
    mv "$cdht" "$CDHISTFILE"
fi

function keep_cd_history() {
    if [ -z "$1" ] ; then d="$HOME" ; else d="$1" ; fi
    cdhcan='readlink -f "$d"'
    if 'cd' "$d"
    then
        echo -e 'date +%s'"\t"$cdhcan >> $CDHISTFILE
    fi
}
function pick_cwd_from_history() {
    f=~/.cdhistgo
    cdhistpick "$f"
    if [ -r "$f" ] ; then cd "'head -1 $f'" ; fi
}

alias cd=keep_cd_history
alias cdh=pick_cwd_from_history

########################################################################

A primeira seção trunca o arquivo de histórico personalizado do mecanismo de histórico de cd se ele ultrapassou 500 linhas desde a última vez que o visualizamos. Não podemos usar o histórico integrado do Bash porque ele não inclui os timestamps, necessários para obter o comportamento "nas últimas três horas".

As duas funções de Bash fazem coisas que não podemos fazer no código Perl abaixo, que de outra forma faz todo o trabalho pesado. O único truque aqui é a chamada readlink , que canaliza os caminhos que você usa. Temos que fazer isso para que cd $HOME ; cd ; cd ~ ; cd ../$USER resulte em 4 instâncias do mesmo caminho no histórico cd , e não em quatro entradas diferentes.

Os alias são apenas invólucros de conveniência para as funções.

Agora, o problema realmente complicado:

#!/usr/bin/perl -w
use strict;
use List::Util qw(min);

#### Configurables #####################################################

# Number of seconds back in time to look for candidate directories
my $history_seconds_threshold = 3 * 60 * 60;

# Ignore directories we have gone to less than this many times
my $access_count_threshold = 1;

# Number of directory options to give in pick list
my $max_choices = 7;


#### DO NOT OPEN. NO USER-SERVICEABLE PARTS INSIDE. ####################

# Get file name our caller wants the cd choice to be sent to
die "usage: $0 <choice_file>\n" unless $#ARGV == 0;
my $cdhg_file = $ARGV[0];
unlink $cdhg_file;      # don't care if it fails

# Build summary stats from history file to find recent most-accessed
my $oldest_interesting = time - $history_seconds_threshold;
my %stats;
open my $cdh, '<', "$ENV{HOME}/.cdhistory" or die "No cd history yet!\n";
while (<$cdh>) {
    chomp;
    my ($secs, $dir) = split /\t/;
    next unless $secs and $secs >= $oldest_interesting;
    ++$stats{$dir};
}

# Assemble directory pick list
my @counts = sort values %stats;
$access_count_threshold = $counts[$max_choices - 1] - 1
        if @counts > $max_choices;
my @dirs = grep { $stats{$_} > $access_count_threshold } keys %stats;
$max_choices = min($max_choices, scalar @dirs);

# Show pick list, and save response to the file pick_cwd_from_history()
# expects.  Why a file?  The shell must call chdir(2), not us, because
# if we do, we change only our CWD.  Can't use stdio; already in use.
my $choice;
if ($max_choices > 1) {
    for (my $i = 0; $i < $max_choices; ++$i) {
        print $i + 1, '. ', $dirs[$i], "\n";
    }
    print "\nYour choice, O splendid one? [1-$max_choices]: ";
    $choice = <STDIN>;
    chomp $choice;
    exit 0 unless $choice =~ /^[0-9]+$/ && $choice <= $max_choices;
}
elsif ($max_choices == 1) {
    print "Would you like to go to $dirs[0]? [y/n]: ";
    $choice = 1 if uc(<STDIN>) =~ /^Y/;
}
else {
    die "Not enough cd history to give choices!\n";
}
if ($choice) {
    open my $cdhg, '>', $cdhg_file or
            die "Can't write to $cdhg_file: $!\n";
    print $cdhg $dirs[$choice - 1], "\n";
}

Salve isso em um arquivo chamado cdhistpick , torne-o executável e coloque-o em algum lugar no seu PATH . Você não vai executá-lo diretamente. Use o cdh alias para isso, pois ele passa em um argumento necessário via pick_cwd_from_history() .

Como isso funciona? Ummmm, exercício para o leitor? :)

Para obter sua primeira exigência, a tecla de atalho, você pode usar qualquer programa de gravação de macro que desejar para o sistema operacional escolhido. Apenas digite cdh e pressione Enter para você. Ou você pode executar cdh , já que é fácil digitar.

Se você quer uma alternativa mais simples, mas menos funcional, que funcionará em qualquer lugar, adquira o hábito de usar o recurso de busca incremental reversa do Bash, Ctrl - R . Pressione isso, então digite "cd" (sem as aspas, mas com o espaço à direita) para ser levado de volta ao comando anterior cd . Então, cada vez que você apertar Ctrl - R , ele retornará ao comando cd antes disso. Dessa forma, você pode retroceder através de todos os comandos cd que você deu, dentro dos limites do recurso de histórico do Bash.

Diga:

$ echo $HISTFILESIZE

para ver quantas linhas de comando o histórico do Bash armazenará para você. Pode ser necessário aumentar isso para manter 3 horas de histórico de comandos.

Para procurar no seu histórico de comandos depois de recuar, pressione Ctrl - S .

Se isso não funcionar em seu sistema, provavelmente é devido a um conflito com o controle de fluxo de software . Você pode consertá-lo com este comando:

$ stty stop undef

Isso impede que o Ctrl-S seja interpretado como o caractere XOFF.

A conseqüência disso é que você não pode mais pressionar Ctrl-S para pausar temporariamente a saída do terminal. Pessoalmente, a última vez que usei isso de propósito foi nos tempos dos modems lentos. Nos dias de hoje com rolagem rápida e grandes buffers de rolagem, eu só uso esse recurso por acidente, então tenho que passar uma segunda lembrança para pressionar Ctrl - Q para obter o terminal não preso. :)

    
por 14.04.2011 / 14:43
0

Use este script . Você precisa instalar o sqlite3 para usá-lo. Ele lança o sqlite3 em subshell para atualizar o banco de dados (para que a mudança para o diretório seja tão rápida quanto com o% normalcd). Baixar este script é source em seu .bashrc . Use o comando c para mudar para diretórios. Se nenhum argumento for dado a c , uma lista ordenada de diretórios mais acessados nos últimos dois dias será exibida no bash. Você pode escolher um.

    
por 30.05.2013 / 06:55