<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>潘锦的空间 &#187; Linux</title>
	<atom:link href="https://www.phppan.com/tag/linux/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.phppan.com</link>
	<description>SaaS SaaS架构 团队管理 技术管理 技术架构 PHP 内核 扩展 项目管理</description>
	<lastBuildDate>Sat, 30 May 2026 09:35:05 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.9.40</generator>
	<item>
		<title>Bash之命令历史的存储和记录</title>
		<link>https://www.phppan.com/2013/02/linux-source-bash-history-command/</link>
		<comments>https://www.phppan.com/2013/02/linux-source-bash-history-command/#comments</comments>
		<pubDate>Mon, 25 Feb 2013 00:34:15 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Bash]]></category>
		<category><![CDATA[Bash源码]]></category>
		<category><![CDATA[history]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[readline]]></category>

		<guid isPermaLink="false">http://www.phppan.com/?p=1801</guid>
		<description><![CDATA[在Bash中我们可以使用 history 命令回顾，修改和重用之前使用过的历史命令。去掉信号机制、去掉作业控制 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>在Bash中我们可以使用 history  命令回顾，修改和重用之前使用过的历史命令。去掉信号机制、去掉作业控制、去掉各种参数调用，今天我们只看下Bash中如何记录命令，如何存储历史命令。</p>
<p>在 Bash 的源代码中，history 命令的定义代码为 builtins/history.def ， builtins  目录下存放的是内部命令的源代码，每个内部命令是一个def文件，如history.def，cd.def等。  Makefile中DEFSRC声明了所有内部命令的def文件。由 mkbuiltins.c 生成编译时辅助工具 mkbuiltins，mkbuiltins 处理  *.def 文件，生成命令的 *.c 源程序以及 builtins.c 、 builtext.h。 builtins.c 和 builtext.h  相当于各个内部命令的索引。</p>
<p>history.def 的作用是解析命令并将不同的参数分发命令到不同的功能实现，如读取命令、覆盖命令等。一些功能实现代码文件在  bashhist.c/bashhist.h，但是关于历史记录的基础操作并不在这两个文件中，它们在 lib/readline 中。这是因为 Bash 采用的<a href="http://tiswww.case.edu/php/chet/readline/rltop.html">GNU Readline函数库</a>中。  Readline提供了统一的行编辑和历史记录功能的命令行交互方式。</p>
<p>history命令在显示时会显示所有的历史记录，这里的所有历史记录包括最开始从文件中读取的历史记录，还包括当前会话产生的记录。假设你的历史记录中已经有了500条命令，如果你用其它文档编辑器将历史日志文件写到1000条，打开终端，你会发现显示的还只有500记录。这是因为在打开终端初始化时，不仅仅有历史记录列表的读操作，还会有关于文件记录数限制的初始化操作，确保文件中的记录条数不会大于设定的最大值。这个初始化操作在  load_history 函数中实现，函数最开始就做了两次历史记录文件的截取操作，一次是默认500，一次是设置的最大值： HISTFILESIZE 。</p>
<p>在历史记录中有一个会话的概念，不同会话中的命令在没有保存到文件前是不会互相冲突的。比如，打开终端A如果你删除 .bash_history  的前10行命令，保存，在命令行中输入history，你会发现输出的命令历史记录并不是从1开始，而是从11开始的。如果此时，你再开一个终端B，输入若干条命令后，再输入history，你会发现历史记录中没有在终端A输入的命令。这是由于在一个终端会话中，历史记录从固化存储位置的读取操作只有一次，写入操作也只有一次，即在打开终端时读取，在关闭终端时写入。</p>
<p>除了文件存储，历史记录也可以记录在MMAP，对应的宏定义为 HISTORY_USE_MMAP。</p>
<p>如果以文件存储方式，命令记录以一行一条命令的方式存储在.bash_history（默认，如果有设置 HISTFILE 则优先使用 HISTFILE  中的值），虽然我们使用 history  命令时看到每条命令前都会有一个标号，我们可以使用　!标号　的方式重新执行命令，这个标号并不是唯一不变的，标号是在初始化时在读取文件时在程序操作中标记的，后续有命令加入时，标号会自增，这个自增并不会受历史记录的最大值限制。</p>
<p>当一次会话退出时保存历史记录文件，将历史数据固化存储，并将会话统计清零。当存储到文件时，Bash  会将此前会话中的命令直接存储到文件末尾，如果文件的记录数大于定义的最大记录数，则清空旧的历史命令，并且当下次再存储时会重写此前文件。代码示例如下：</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="c" style="font-family:monospace;">      <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>history_lines_this_session <span style="color: #339933;">&lt;=</span> where_history <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> force_append_history<span style="color: #009900;">&#41;</span>
        append_history <span style="color: #009900;">&#40;</span>history_lines_this_session<span style="color: #339933;">,</span> hf<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #b1b100;">else</span>
        write_history <span style="color: #009900;">&#40;</span>hf<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
      sv_histsize <span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;HISTFILESIZE&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>存储操作最终还是归集于存储介质的读写操作，如对文件的读写，增加的只是对业务逻辑规则的各种限制。命令可以在执行命令时记录，也可以在命令刚输入，但已经识别的情况下记录，Bash  属于后者。 Bash 在 yacc 做语法分析时将用户输入的命令通过 maybe_add_history  函数写入到当前会话的命令历史记录表中。在做语法分析时就已经记录了用户输入的命令，此时记录就不用管命令最终的结果是怎样，也不用管如果执行过程出了异常会怎样处理。它只是如实的在执行前记录用户输入的什么命令，由此，我们可以定义  Bash 的命令历史记录的定义为用户输入的命令历史记录。</p>
<p>参考资料： http://files.linjian.org/articles/techreport/bash_study.tar.gz</p>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2013/02/linux-source-bash-history-command/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
