列印訪問次數最多的目錄的 Shell 腳本
有沒有辦法編寫具有以下功能的 bash 腳本?
- 當我按下某個鍵或組合鍵時啟動。(不是那麼重要的要求)
- 確定過去 3 小時內訪問量最大的 7 個目錄。
- 向我提供這 7 個目錄的列表,以便我可以使用 tab 和 shift-tab(向後)循環瀏覽它們。然後按輸入將意味著 cd 到所選目錄。
謝謝
將以下內容添加到您的
~/.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 程式碼中無法完成的事情,否則會完成所有繁重的工作。這裡唯一棘手的一點是
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
自己執行,因為它很容易輸入。如果您想要一個更簡單但功能較少但可以在任何地方使用的替代方案,請養成使用 Bash 的反向增量搜尋功能的習慣
Ctrl
-R
。按下它,然後鍵入“cd”(不帶引號,但帶有尾隨空格)以返回上一個cd
命令。然後每次你點擊Ctrl
-R
,它都會帶你回到cd
之前的命令。通過這種方式,您可以在 Bash 歷史功能的限制範圍內向後遍歷cd
您給出的所有命令。說:
$ echo $HISTFILESIZE
查看 Bash 歷史記錄將為您儲存多少命令行。您可能需要增加此值以保存 3 小時的命令歷史記錄。
要在向後搜尋命令歷史記錄後向前搜尋,請按
Ctrl
-S
。如果這在您的系統上不起作用,則可能是由於與軟體流控制衝突。您可以使用以下命令修復它:
$ stty stop undef
這可以防止 Ctrl-S 被解釋為 XOFF 字元。
這樣做的結果是您不能再按 Ctrl-S 來暫時暫停終端輸出。就個人而言,我最後一次故意使用它是在慢調製解調器時代。這些天來快速滾動和大回滾緩衝區,我只是偶然使用這個功能,然後不得不花一秒鐘記住按下
Ctrl
-Q
讓終端不卡住。:)