Shell 脚本打印最常访问的目录

Shell 脚本打印最常访问的目录

有没有办法编写具有以下功能的bash脚本?

  1. 当我按下某个键或组合键时启动。 (不是那么重要的要求)
  2. 确定过去 3 小时内访问量最大的 7 个目录。
  3. 向我提供这 7 个目录的列表,以便我可以使用 tab 和 shift-tab(向后)循环浏览它们。然后按 Enter 键就意味着 cd 到所选目录。

谢谢

答案1

将以下内容添加到您的~/.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

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

如果自上次查看以来 cd 历史记录机制的自定义历史记录文件变得超过 500 行,第一部分将截断该文件。我们无法使用 Bash 的内置历史记录,因为它不包含时间戳,而您需要时间戳才能获得“过去 3 小时内”的行为。

这两个 Bash 函数完成了我们在下面的 Perl 代码中无法完成的事情,否则 Perl 代码会完成所有繁重的工作。这里唯一棘手的一点是readlink调用,它将您使用的路径规范化。我们必须这样做,以便在历史记录cd $HOME ; cd ; cd ~ ; cd ../$USER中产生相同路径的 4 个实例cd,而不是四个不同的条目。

别名只是函数的方便包装。

现在真正棘手的一点是:

#!/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";
}

将其保存到名为 的文件中cdhistpick,使其可执行,然后将其放在PATH.您不会直接执行它。cdh为此使用别名,因为它通过 传递必要的参数pick_cwd_from_history()

它是如何工作的?嗯,给读者做练习? :)

为了满足您的第一个要求(热键),您可以使用适合您选择的操作系统的任何宏录制程序。只需让其为您输入cdh并按下即可。Enter或者,您可以cdh自己运行,因为它很容易输入。

Ctrl如果您想要一个更简单但功能较少且可在任何地方使用的替代方案,请养成使用 Bash 的反向增量搜索功能-的习惯R。按该键,然后输入“cd”(不带引号,但尾随空格)以返回到上一个cd命令。然后每次你点击Ctrl- R,它都会带你回到cd之前的命令。通过这种方式,您可以cd在 Bash 历史记录功能的范围内向后浏览您给出的所有命令。

说:

$ echo $HISTFILESIZE

查看 Bash 历史记录将为您存储多少条命令行。您可能需要增加此值以保存 3 小时的命令历史记录。

要在向后浏览命令历史记录后向前搜索,请按Ctrl- S

如果这在您的系统上不起作用,可能是由于与软件流量控制。您可以使用以下命令修复它:

$ stty stop undef

这可以防止 Ctrl-S 被解释为 XOFF 字符。

这样做的结果是您不能再按 Ctrl-S 来暂时暂停终端输出。就我个人而言,我上次故意使用它是在慢速调制解调器时代。如今,随着快速滚动和大回滚缓冲区的出现,我只是偶然使用此功能,然后必须花一秒钟记住按下Ctrl-Q以使终端不再卡住。 :)

答案2

使用这个脚本。您需要安装sqlite3才能使用它。它在子 shell 中启动 sqlite3 来更新数据库(以便更改目录与​​正常情况一样快cd)。下载这个脚本是source在你的.bashrc.使用命令c更改目录。如果没有给出参数,c那么 bash 上将显示最近两天访问最多的目录的排序列表。你可以选一个。

相关内容