bash多終端history紀錄如何存儲及行為


一、為什么有這個問題

在一台服務器上,可能存在多個用戶共用一個賬號的問題;或者使用同一個用戶打開多個終端,這些終端就構成了很多的會話(session)。當然這些會話在使用的過程中必然不會相互干擾,問題在於它們生成的歷史記錄該如何相互交互?
下面分析結合bash4.0源碼分析。

二、history的存儲位置

通過bash的代碼可以看到,bash文件使用的是環境變量HISTFILE來控制寫入文件的。通過bash的man手冊可以看到
HISTFILE
The name of the file in which command history is saved (see HISTORY below). The default value is ~/.bash_history. If unset, the command history is not saved when an inter‐
active shell exits.
也就是說,默認是保存在"~/.bash_history"文件中。

三、history文件的行為

同樣是在bash的man手冊中,可以看到關於history的說明。
啟動時,HISTFILE的內容會被讀取(On startup, the history is initialized from the file named by the variable HISTFILE (default ~/.bash_history))
(交互式shell)退出時,最IN的%HISTSIZE行會被拷貝到HISTFILE文件中。如果histappend選項使能的話,這些行會追加到歷史文件中,否則history文件會被重寫( When an interactive shell exits, the last $HISTSIZE lines are copied from the history list to $HISTFILE. If the histappend shell option is enabled (see the description of shopt
under SHELL BUILTIN COMMANDS below), the lines are appended to the history file, otherwise the history file is overwritten. If HISTFILE is unset, or if the history file is
unwritable, the history is not saved. )

HISTORY
When the -o history option to the set builtin is enabled, the shell provides access to the command history, the list of commands previously typed. The value of the HISTSIZE vari‐
able is used as the number of commands to save in a history list. The text of the last HISTSIZE commands (default 500) is saved. The shell stores each command in the history list
prior to parameter and variable expansion (see EXPANSION above) but after history expansion is performed, subject to the values of the shell variables HISTIGNORE and HISTCONTROL.

On startup, the history is initialized from the file named by the variable HISTFILE (default ~/.bash_history). The file named by the value of HISTFILE is truncated, if necessary,
to contain no more than the number of lines specified by the value of HISTFILESIZE. When the history file is read, lines beginning with the history comment character followed imme‐
diately by a digit are interpreted as timestamps for the preceding history line. These timestamps are optionally displayed depending on the value of the HISTTIMEFORMAT variable.
When an interactive shell exits, the last $HISTSIZE lines are copied from the history list to $HISTFILE. If the histappend shell option is enabled (see the description of shopt
under SHELL BUILTIN COMMANDS below), the lines are appended to the history file, otherwise the history file is overwritten. If HISTFILE is unset, or if the history file is
unwritable, the history is not saved. If the HISTTIMEFORMAT variable is set, time stamps are written to the history file, marked with the history comment character, so they may be
preserved across shell sessions. This uses the history comment character to distinguish timestamps from other history lines. After saving the history, the history file is trun‐
cated to contain no more than HISTFILESIZE lines. If HISTFILESIZE is not set, no truncation is performed.

The builtin command fc (see SHELL BUILTIN COMMANDS below) may be used to list or edit and re-execute a portion of the history list. The history builtin may be used to display or
modify the history list and manipulate the history file. When using command-line editing, search commands are available in each editing mode that provide access to the history
list.

The shell allows control over which commands are saved on the history list. The HISTCONTROL and HISTIGNORE variables may be set to cause the shell to save only a subset of the com‐
mands entered. The cmdhist shell option, if enabled, causes the shell to attempt to save each line of a multi-line command in the same history entry, adding semicolons where neces‐
sary to preserve syntactic correctness. The lithist shell option causes the shell to save the command with embedded newlines instead of semicolons. See the description of the
shopt builtin below under SHELL BUILTIN COMMANDS for information on setting and unsetting shell options.

四、bash4.0的代碼看

可以看到,是追加還是重寫是通過下面的邏輯判斷實現的
history_lines_this_session <= where_history () || force_append_history
其中的邏輯判斷是histappend選項,history_lines_this_session是這個session生成的(新輸入的)命令集合,而where_history ()是整個history文件的大小。通常情況下(如果沒有設置實時讀取history等騷操作)下,這個條件也是滿足的,所以即使沒有設置這個histappend,常規行為也是會追加而不是覆蓋

bash-4.0\bashhist.c
/* If this is an interactive shell, then append the lines executed
this session to the history file. */
int
maybe_save_shell_history ()
{
int result;
char *hf;

result = 0;
if (history_lines_this_session)
{
hf = get_string_value ("HISTFILE");

if (hf && *hf)
{
/* If the file doesn't exist, then create it. */
if (file_exists (hf) == 0)
{
int file;
file = open (hf, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (file != -1)
close (file);
}

/* Now actually append the lines if the history hasn't been
stifled. If the history has been stifled, rewrite the
history file. */
using_history ();
if (history_lines_this_session <= where_history () || force_append_history)
{
result = append_history (history_lines_this_session, hf);
history_lines_in_file += history_lines_this_session;
}
else
{
result = write_history (hf);
history_lines_in_file = history_lines_this_session;
}
history_lines_this_session = 0;

sv_histsize ("HISTFILESIZE");
}
}
return (result);
}

五、測試

1、第一個終端執行命令

tsecer@harry.term1: shopt -u histappend
tsecer@harry.term1: shopt histappend
histappend off
tsecer@harry.term1: echo after histappend off in term1
after histappend off in term1
tsecer@harry.term1:

2、第二個終端執行命令

tsecer@harry.term2: shopt -u histappend
tsecer@harry.term2: shopt histappend
histappend off
tsecer@harry.term2: echo histappend after term2
histappend after term2
tsecer@harry.term2:

3、分別exit兩個終端,並在第三個終端中查看歷史記錄

可以同時看到兩個終端的輸出。
shopt -u histappend
shopt histappend
echo after histappend off in term1
exit
shopt -u histappend
shopt histappend
echo histappend after term2
exit

六、多環境下配置建議

1、強制追加模式

之前只是說常規情況下歷史記錄都是追加的,但是還是開啟histappen的容錯性更好。

2、命令時間戳

遺憾的是bash並不支持記錄命令在哪個終端鍵入的,所以最好在基類命令的執行時間,從而在合並之后可以追溯到歷史時間。
HISTTIMEFORMAT
If this variable is set and not null, its value is used as a format string for strftime(3) to print the time stamp associated with each history entry displayed by the history
builtin. If this variable is set, time stamps are written to the history file so they may be preserved across shell sessions. This uses the history comment character to
distinguish timestamps from other history lines.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM