シェルスクリプトは、最も訪問されたディレクトリを印刷します。

シェルスクリプトは、最も訪問されたディレクトリを印刷します。

次の機能を使用してbashスクリプトを作成する方法はありますか?

  1. 特定のキーまたはキーの組み合わせを押すと実行されます。 (それほど重要な要件ではない)
  2. 過去3時間で最も訪問された7つのディレクトリを識別します。
  3. タブとShift-Tab(戻る)を使用して循環できるように、この7つのディレクトリのリストを提供してください。次に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時間」の動作を取得するために必要なタイムスタンプが含まれていないため、使用できません。

これら2つのBash関数は、以下のPerlコードでは実行できないことを行います。それ以外の場合は、すべての重い作業を実行します。ここで唯一トリッキーな部分は、readlink使用するパスを正規化する呼び出しです。これは、履歴に4つの異なるエントリではなく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これにより、cdBashの履歴機能の範囲内で指定したすべてのコマンドを逆に操作できます。

説明する:

$ echo $HISTFILESIZE

Bashの履歴がどのくらいのコマンドラインを保存するかを確認してください。 3時間のコマンド履歴を保存するには、この値を増やす必要があります。

コマンド履歴を後ろに検索してから前方に検索するには、Ctrl-を押しますS

これがあなたのシステムで機能しない場合、その理由は次のとおりです。ソフトウェアフロー制御。次のコマンドを使用して問題を解決できます。

$ stty stop undef

これにより、Ctrl-SがXOFF文字と​​して解釈されるのを防ぎます。

その結果、Ctrl-Sを押して端末出力を一時的に一時停止することはできません。個人的に最後に意図的に使用したのは遅いモデム時代でした。最近では、高速スクロールと大きなスクロールバックバッファの出現で、この機能を時々使用してからしばらく時間をかけて押す必要があることを覚えておく必要がありますCtrlQだからターミナルが止まらない。 :)

答え2

使用このスクリプトsqlite3使用するにはインストールする必要があります。データベースを更新するには、サブシェルでsqlite3を起動します(ディレクトリの変更は通常どおり高速ですcd)。ディレクトリを変更するには、コマンドを使用してこのスクリプトをダウンロードしてくださいsource。引数が指定されていない場合は、過去2日間に最も訪問されたディレクトリのソートされたリストがbashに表示されます。 1つを選択できます。.bashrccc

関連情報