原理到實(shí)戰(zhàn)技巧)
1. history 命令到底是什么很多 Linux 新手第一次接觸history命令時(shí)覺(jué)得它就是個(gè)“查聊天記錄”的小工具敲一下回車把自己最近執(zhí)行過(guò)的命令列出來(lái)。這個(gè)理解沒(méi)錯(cuò)但遠(yuǎn)遠(yuǎn)不夠。history是 Bash 等 Shell 內(nèi)置的歷史記錄功能。你在終端里敲過(guò)的每一條命令只要是在交互式 Shell 中執(zhí)行的默認(rèn)都會(huì)被記到內(nèi)存里的歷史列表中退出終端時(shí)再追加寫入到家目錄下的~/.bash_history文件。它解決的痛點(diǎn)是你昨天下午到底執(zhí)行過(guò)哪條命令那個(gè)跑到一半的 Python 腳本是怎么啟動(dòng)的上周三你改過(guò)哪個(gè)配置文件一條history就能給你完整答案不需要靠腦子回憶。這個(gè)功能在三種人手里價(jià)值完全不同開(kāi)發(fā)人員找回之前執(zhí)行過(guò)的長(zhǎng)命令不用重復(fù)輸入CtrlR 反向搜索一下就能撈出來(lái)。運(yùn)維工程師排查系統(tǒng)故障時(shí)通過(guò)歷史記錄復(fù)盤之前的操作路徑。系統(tǒng)出問(wèn)題往往不是無(wú)緣無(wú)故的一翻歷史就知道是誰(shuí)、在什么時(shí)候、執(zhí)行了什么操作。面試求職者面試官非常愛(ài)拿history相關(guān)的用法來(lái)測(cè)你的命令功底比如追問(wèn)“!!代表什么”“怎么讓命令記錄帶時(shí)間戳”這類問(wèn)題答不上來(lái)很容易暴露基本功薄弱。這篇文章我會(huì)從原理講到實(shí)戰(zhàn)把history命令的常用操作、進(jìn)階技巧、踩坑記錄和面試考點(diǎn)一次說(shuō)透。無(wú)論你是剛接觸 Linux 的初學(xué)者還是已經(jīng)寫了幾年腳本的老手應(yīng)該都能從中找到給自己用的東西。2. 從原理看歷史記錄它到底存哪兒了2.1 Bash 的“內(nèi)存文件”雙重機(jī)制理解history的第一步是先搞清楚它的存儲(chǔ)機(jī)制。Bash 在運(yùn)行時(shí)每條交互式命令會(huì)先存進(jìn)當(dāng)前 Shell 進(jìn)程的內(nèi)存緩沖區(qū)你輸入history看到的就是這個(gè)內(nèi)存里的列表。當(dāng)你正常退出 Shell 時(shí)比如輸入exit或者按 CtrlDBash 才會(huì)把當(dāng)前會(huì)話新增的命令追加到~/.bash_history文件里。這個(gè)機(jī)制帶來(lái)的直接后果是如果你用kill -9強(qiáng)制殺掉終端進(jìn)程或者終端窗口被直接關(guān)閉嚴(yán)格來(lái)說(shuō)很多終端模擬器在窗口關(guān)閉時(shí)會(huì)向 Shell 發(fā)送 SIGHUPBash 在收到 SIGHUP 時(shí)仍會(huì)寫入歷史但如果是瞬時(shí)斷電、系統(tǒng)崩潰、SSH 連接被粗暴斷開(kāi)就很有可能丟失那么本次會(huì)話中執(zhí)行過(guò)的命令就不會(huì)被寫入文件下次打開(kāi)終端時(shí)你什么都查不到。我見(jiàn)過(guò)不少運(yùn)維同事在排查線上事故時(shí)發(fā)現(xiàn)歷史記錄里缺少了最關(guān)鍵那幾條命令一問(wèn)才知道當(dāng)時(shí)是在緊急狀態(tài)下強(qiáng)殺會(huì)話跑路結(jié)果把證據(jù)給丟了。這個(gè)坑在演練環(huán)境踩一次比讀十篇文檔都管用。2.2 環(huán)境變量控制的三個(gè)關(guān)鍵參數(shù)Bash 的歷史記錄行為由幾個(gè)環(huán)境變量控制理解它們就能精準(zhǔn)定制history的脾氣環(huán)境變量默認(rèn)值作用HISTSIZE1000當(dāng)前會(huì)話內(nèi)存中最多保存的歷史條數(shù)HISTFILESIZE2000歷史文件~/.bash_history中最多保存的條數(shù)HISTFILE~/.bash_history指定歷史記錄文件的位置HISTCONTROL無(wú)默認(rèn)忽略重復(fù)控制歷史記錄的過(guò)濾規(guī)則HISTTIMEFORMAT空設(shè)置歷史記錄的時(shí)間戳顯示格式這里的重點(diǎn)在于HISTSIZE和HISTFILESIZE的區(qū)別。HISTSIZE管的是內(nèi)存中的條數(shù)HISTFILESIZE管的是文件中的條數(shù)。即使你在當(dāng)前會(huì)話中執(zhí)行了 5000 條命令HISTSIZE只有 1000 的話內(nèi)存里也只留最近 1000 條退出時(shí)寫入文件的記錄數(shù)受HISTFILESIZE限制。在實(shí)際工作中我更推薦把這兩個(gè)值調(diào)大一些尤其對(duì)于運(yùn)維來(lái)說(shuō)歷史記錄就是操作審計(jì)的依據(jù)export HISTSIZE10000 export HISTFILESIZE20000這兩行可以寫進(jìn)~/.bashrc。不過(guò)要注意文件太大之后每次打開(kāi)終端 Bash 都要讀取整個(gè)歷史文件啟動(dòng)速度會(huì)略有下降所以也別無(wú)腦調(diào)到幾十萬(wàn)條一萬(wàn)到兩萬(wàn)這個(gè)區(qū)間是比較合理的平衡點(diǎn)。2.3 為什么有時(shí)候命令會(huì)憑空消失除了強(qiáng)殺進(jìn)程之外還有一個(gè)非常隱蔽的原因會(huì)導(dǎo)致歷史記錄丟失多個(gè)終端窗口同時(shí)打開(kāi)并正常退出時(shí)后退出的那個(gè)窗口會(huì)覆蓋先退出的窗口寫入的內(nèi)容。舉個(gè)例子。你開(kāi)了兩個(gè)終端終端 A 執(zhí)行了 20 條命令終端 B 執(zhí)行了 10 條命令。兩個(gè)終端的內(nèi)存歷史列表在啟動(dòng)時(shí)都是從同一個(gè)~/.bash_history文件讀出來(lái)的副本。終端 A 退出時(shí)它把內(nèi)存里的全部歷史包括 B 后來(lái)執(zhí)行的原樣寫回文件看起來(lái)沒(méi)問(wèn)題。但如果 B 先退出B 把只包含自己會(huì)話命令的內(nèi)存列表寫回文件等 A 再退出時(shí)A 也會(huì)寫一遍——問(wèn)題來(lái)了A 的內(nèi)存列表里沒(méi)有 B 執(zhí)行的那 10 條這個(gè)覆蓋過(guò)程就把 B 的歷史抹掉了。這個(gè)坑在團(tuán)隊(duì)協(xié)作服務(wù)器上非常常見(jiàn)我線下排查時(shí)親手救過(guò)一次“歷史記錄神秘丟失”的案子最后定位到就是多窗口覆蓋。解決思路是設(shè)置HISTCONTROL并用shopt -s histappend開(kāi)啟追加模式后面第 4 章會(huì)專門展開(kāi)講。3. 高頻實(shí)操把 history 用到極致3.1 最基礎(chǔ)的幾個(gè)調(diào)用姿勢(shì)先把最基本的用法過(guò)一遍這些都是面試和日常操作中最高頻的。history直接回車顯示全部歷史記錄每條前面帶一個(gè)編號(hào)501 ls -lh /var/log/ 502 tail -f /var/log/messages 503 systemctl status nginx帶數(shù)字參數(shù)history 20表示只顯示最近 20 條這個(gè)在屏幕比較小或者歷史很長(zhǎng)時(shí)非常實(shí)用。按編號(hào)執(zhí)行歷史中的命令用!編號(hào)這種“感嘆號(hào)編號(hào)”的語(yǔ)法!503這會(huì)在當(dāng)前 Shell 中重新執(zhí)行編號(hào)為 503 的那條命令也就是systemctl status nginx。執(zhí)行前 Bash 會(huì)把命令原樣回顯出來(lái)方便你確認(rèn)是不是自己要的那條。!!代表上一條命令兩個(gè)感嘆號(hào)最常見(jiàn)的場(chǎng)景是sudo apt install nginx # 提示權(quán)限不足 sudo !!這個(gè)用在忘記加sudo時(shí)救場(chǎng)非???。!字符串則代表最近一條以指定字符串開(kāi)頭的命令比如!systemctl會(huì)執(zhí)行最近一次執(zhí)行過(guò)的以systemctl開(kāi)頭的命令。3.2 歷史記錄去重和時(shí)間戳顯示默認(rèn)情況下Bash 會(huì)記錄連續(xù)重復(fù)執(zhí)行的命令你連續(xù)敲三次ls歷史里就會(huì)出現(xiàn)三條ls。這在回顧操作時(shí)非常煩人明明想知道當(dāng)時(shí)執(zhí)行過(guò)什么步驟結(jié)果屏幕上全是重復(fù)的無(wú)效信息。配置HISTCONTROL可以解決這個(gè)問(wèn)題。它有多個(gè)選項(xiàng)值比較常用的是組合設(shè)置export HISTCONTROLignoredups:erasedups兩個(gè)選項(xiàng)的含義ignoredups忽略連續(xù)重復(fù)的命令也就是說(shuō)你連著敲三遍ls歷史里只記一次。erasedups整個(gè)歷史列表中如果某條命令已經(jīng)出現(xiàn)過(guò)再次執(zhí)行時(shí)會(huì)把前面那條舊記錄刪掉只保留最新一條。我用的是ignoredups:erasedups組合這樣歷史列表既干凈又完整。如果你希望某些敏感命令不被記錄比如帶密碼的登錄命令可以在命令前面加一個(gè)空格配合ignorespace選項(xiàng)export HISTCONTROLignorespace設(shè)置了ignorespace之后以空格開(kāi)頭的命令就不會(huì)進(jìn)入歷史記錄。這個(gè)技巧在臨時(shí)執(zhí)行含密碼、Token 的連接命令時(shí)非常有用。不過(guò)這里要提醒一句HISTCONTROL中的ignorespace只對(duì)當(dāng)前 Bash 會(huì)話有效如果別人拿到你的 Shell 環(huán)境也可以把它取消掉再翻看歷史所以它只能防粗心不能防有心。時(shí)間戳是另一個(gè)剛需。默認(rèn)的歷史記錄只顯示命令本身不顯示執(zhí)行時(shí)間。排查故障時(shí)你看到一條rm -rf /tmp/cache根本不知道它是什么時(shí)候執(zhí)行的時(shí)間對(duì)不上定位問(wèn)題就無(wú)從談起。配置時(shí)間戳一行搞定export HISTTIMEFORMAT%F %T %F表示日期年-月-日%T表示時(shí)間時(shí):分:秒。設(shè)置完再執(zhí)行history輸出會(huì)變成508 2025-11-20 14:22:33 systemctl status nginx 509 2025-11-20 14:23:01 tail -f /var/log/messages注意一個(gè)細(xì)節(jié)HISTTIMEFORMAT設(shè)置生效之前的歷史記錄由于沒(méi)有存儲(chǔ)時(shí)間戳顯示時(shí)會(huì)統(tǒng)一顯示為設(shè)置生效那一刻的時(shí)間看起來(lái)會(huì)比較怪但這不影響新記錄的正確性。3.3 CtrlR 反向搜索和 fc 編輯器history命令本身只是在“查看”歷史日常真正高頻使用的是在 Bash 交互環(huán)境中按CtrlR啟動(dòng)反向增量搜索。按完CtrlR之后輸入關(guān)鍵詞Bash 會(huì)實(shí)時(shí)匹配最近的符合條件的命令按一次CtrlR跳到更早一條匹配項(xiàng)找到之后按回車直接執(zhí)行或者按方向鍵編輯后再執(zhí)行。舉個(gè)例子你想找之前跑過(guò)的一條帶--exclude參數(shù)的tar命令只記得里面有“exclude”這個(gè)關(guān)鍵詞。按CtrlR輸入excluBash 立刻顯示匹配結(jié)果(reverse-i-search)exclu: tar czf /backup/app.tar.gz --exclude*.log /data/app這個(gè)操作比history | grep快得多因?yàn)樗窃隽科ヅ浣g盡腦汁想命令的時(shí)候敲幾個(gè)字母就能撈回來(lái)。fc是另一個(gè)容易被忽略但很好用的內(nèi)置命令它用來(lái)“進(jìn)入編輯器編輯歷史命令”。執(zhí)行fc -l相當(dāng)于查看歷史fc -l -10查看最近 10 條。最有價(jià)值的用法是組合fc -s gcc這條命令的意思是以最近一次以“gcc”開(kāi)頭的命令為基礎(chǔ)打開(kāi)編輯器讓你修改保存退出后立即執(zhí)行。在需要反復(fù)調(diào)整一個(gè)長(zhǎng)編譯參數(shù)時(shí)這比一次次CtrlR翻找再手動(dòng)改要順手得多。我以前遇到一個(gè)情況一條長(zhǎng)達(dá)幾百個(gè)字符的rsync同步命令因?yàn)槁窂絽?shù)天天變每天都要重新敲一遍。后來(lái)改成fc -s rsync進(jìn)編輯器改路徑效率提升非常明顯。4. 進(jìn)階玩法共享歷史與安全審計(jì)4.1 解決多終端歷史覆蓋問(wèn)題前面提到過(guò)多個(gè)終端同時(shí)開(kāi)著歷史記錄會(huì)被后退出者覆蓋。徹底解決這個(gè)問(wèn)題需要用兩個(gè)配置組合。第一步啟用 Bash 的追加模式shopt -s histappend這一步讓每條命令在執(zhí)行后立即以追加方式寫入歷史文件而不是等退出時(shí)才整體寫入。這樣即使多個(gè)終端同時(shí)開(kāi)著每條命令也能實(shí)時(shí)落盤互不覆蓋。第二步設(shè)置 PROMPT_COMMAND 鉤子讓每次敲回車后自動(dòng)把新命令同步到歷史文件export PROMPT_COMMANDhistory -a; history -c; history -r這里三個(gè)子命令的含義分別是history -a把當(dāng)前會(huì)話中新增的命令追加寫入歷史文件。history -c清空當(dāng)前 Shell 內(nèi)存中的歷史列表。history -r從歷史文件重新讀取全部歷史到內(nèi)存。這三個(gè)動(dòng)作組合起來(lái)的效果是每次執(zhí)行完一條命令Bash 立即把新增歷史寫入公共文件同時(shí)清空并重讀文件內(nèi)容。這樣任何一個(gè)終端都能實(shí)時(shí)看到其他終端執(zhí)行過(guò)的命令歷史記錄徹底打通。這種方式在多人共用同一臺(tái)服務(wù)器時(shí)可以顯著減少“找不到是誰(shuí)執(zhí)行了什么操作”的問(wèn)題。但也要提醒操作記錄全透明意味著“裸奔”如果服務(wù)器是團(tuán)隊(duì)共享的大家執(zhí)行的每個(gè)操作都被記錄下來(lái)這本身有正反兩面至少要對(duì)每條命令負(fù)責(zé)。4.2 讓歷史記錄不可篡改的思路審計(jì)類的需求場(chǎng)景下運(yùn)維經(jīng)常需要保證history不能被普通用戶隨意修改、清空。常見(jiàn)的加固思路是把歷史文件設(shè)為只讀或者限制普通用戶修改自己 home 目錄下歷史記錄的權(quán)限。但從技術(shù)上說(shuō)用戶對(duì)自己 home 目錄下的文件和當(dāng)前 Shell 有完全控制權(quán)任何“只讀”設(shè)置都可以被他自己改回來(lái)所以只能防君子不能防小人。實(shí)際工作中更合理的方案是依賴系統(tǒng)級(jí)別的審計(jì)機(jī)制把用戶執(zhí)行的命令記錄到單獨(dú)的日志文件。比如通過(guò) Bash 的 PROMPT_COMMAND 結(jié)合 logger 命令把每條命令實(shí)時(shí)發(fā)給 syslogexport PROMPT_COMMANDhistory -a /dev/null; logger -p authpriv.info command: $(history 1)這樣每條命令都會(huì)附帶用戶和終端信息寫入系統(tǒng)日志即使~/.bash_history被清空命令記錄仍然存在于/var/log/secure或/var/log/auth.log中。當(dāng)然這種做法本身也有局限性Linux 系統(tǒng)的審計(jì)記錄內(nèi)容龐雜真要溯源還是要配合其他工具但至少歷史命令不會(huì)因?yàn)槲募磺蹇斩鴱氐紫А2贿^(guò)這類加固配置不在本文展開(kāi)用得少反而容易出配置錯(cuò)誤。對(duì)于絕大多數(shù)普通使用者了解“歷史記錄存在哪、如何讓記錄帶時(shí)間戳、如何避免覆蓋丟失”已經(jīng)足夠了。4.3 終端復(fù)用器與 history 的交互用 tmux 或 screen 的人越來(lái)越多它們本身也是多會(huì)話工作模式。在 tmux 里開(kāi)多個(gè)窗口時(shí)每個(gè)窗口都是獨(dú)立的 Bash 會(huì)話如果不做額外配置每個(gè)窗格的歷史記錄仍然是“各記各的”退出時(shí)同樣存在覆蓋問(wèn)題。用了前面提到的shopt -s histappend之后這個(gè)問(wèn)題就自然解決了。另外一點(diǎn)tmux 會(huì)話崩潰或誤殺時(shí)Bash 會(huì)話可能會(huì)收到非正常信號(hào)導(dǎo)致歷史丟失。雖然 tmux 本身有會(huì)話恢復(fù)功能但歷史記錄能否保住最終取決于 Bash 的寫入時(shí)機(jī)。建議在 tmux 里同樣配置 PROMPT_COMMAND 的實(shí)時(shí)寫入方案這樣就算 tmux 崩了歷史也早就寫到文件里了。5. 常見(jiàn)問(wèn)題與排錯(cuò)技巧實(shí)錄5.1 速查表常見(jiàn)問(wèn)題與解決方案整理一份我在實(shí)際使用中反復(fù)遇到的history相關(guān)問(wèn)題和對(duì)應(yīng)解法直接存下來(lái)就能當(dāng)備忘錄用問(wèn)題現(xiàn)象原因解決方案歷史記錄為空或突然少了很多強(qiáng)殺進(jìn)程、連接斷開(kāi)導(dǎo)致未寫入配置shopt -s histappend PROMPT_COMMAND 實(shí)時(shí)寫入多個(gè)終端退出后歷史相互覆蓋Bash 默認(rèn)退出時(shí)才整體寫入文件追加模式 history -a / -c / -r組合歷史命令沒(méi)有時(shí)間未設(shè)置HISTTIMEFORMAT加export HISTTIMEFORMAT%F %T 歷史中大量重復(fù)命令未配置去重設(shè)置HISTCONTROLignoredups:erasedups不想某條命令進(jìn)歷史沒(méi)有過(guò)濾機(jī)制命令前加空格 HISTCONTROLignorespacehistory顯示不全文件行數(shù)超過(guò)HISTFILESIZE調(diào)大HISTFILESIZE5.2 敏感信息泄露密碼出現(xiàn)在歷史里怎么處理這是我在實(shí)戰(zhàn)中踩過(guò)最深的一個(gè)坑。有一次排查問(wèn)題我發(fā)現(xiàn)自己的 MySQL 密碼被明文記錄在~/.bash_history文件里原因是當(dāng)時(shí)用了mysql -uroot -p123456這種寫密碼的方式。這樣一個(gè)文件如果被別人看到整個(gè)數(shù)據(jù)庫(kù)就相當(dāng)于裸奔。處理已經(jīng)寫進(jìn)歷史的敏感命令辦法很直接。先用history找到那條命令的編號(hào)比如是 520history -d 520history -d從內(nèi)存和文件中同時(shí)刪除對(duì)應(yīng)編號(hào)的記錄。但要注意其他會(huì)話可能已經(jīng)把這條命令寫入歷史文件了所以最穩(wěn)妥的做法是直接編輯~/.bash_history文件用 vim 刪掉含有敏感信息的行。這個(gè)文件在每次 Bash 啟動(dòng)時(shí)被讀入內(nèi)存當(dāng)前會(huì)話需要history -r重新加載才能同步。更重要的還是防患于未然。一旦意識(shí)到某條命令包含密碼、Token、私鑰路徑等敏感信息就不要再敲了。養(yǎng)成好習(xí)慣所有需要登錄的命令一律用交互式輸入密碼或者把密碼放在環(huán)境變量中讀取。這兩種方式都不會(huì)讓密碼直接出現(xiàn)在命令里。5.3 history 在腳本和 crontab 中為什么不可用很多人踩過(guò)這個(gè)坑寫了一個(gè) Shell 腳本在腳本里調(diào)用history命令結(jié)果什么都沒(méi)輸出。這不是命令壞了而是因?yàn)閔istory只對(duì)交互式 Shell 的會(huì)話起作用。在非交互式 Shell比如腳本執(zhí)行、crontab 任務(wù)中Bash 默認(rèn)不加載歷史記錄也不會(huì)把命令寫入歷史文件。在腳本中需要讀取歷史時(shí)可以通過(guò)HISTFILE環(huán)境變量手動(dòng)指定歷史文件然后使用fc -l或history來(lái)讀取#!/bin/bash HISTFILE~/.bash_history history但這種方式讀出來(lái)的是整個(gè)歷史文件在腳本里直接處理文本反而更簡(jiǎn)單直接cat ~/.bash_history再 grep 就行。我個(gè)人在寫審計(jì)腳本時(shí)更常用的是直接讀文件配合 awk、grep 處理沒(méi)必要繞一圈走h(yuǎn)istory。另一個(gè)相關(guān)場(chǎng)景是 cron 任務(wù)里需要用!!或!$這一類的歷史展開(kāi)符號(hào)這些在非交互式 Shell 中同樣無(wú)效因?yàn)楦緵](méi)有歷史記錄可展開(kāi)。寫腳本時(shí)不要依賴這類快捷符號(hào)老老實(shí)實(shí)把完整命令寫出來(lái)避免“腳本在終端手動(dòng)執(zhí)行正常一掛 cron 就神秘失敗”的詭異問(wèn)題。5.4 歷史文件損壞的一種真實(shí)案例有一次我在一臺(tái)長(zhǎng)期運(yùn)行的服務(wù)器上發(fā)現(xiàn)history命令執(zhí)行起來(lái)特別慢而且經(jīng)常出現(xiàn)“某一條命令后接了一串亂碼”的情況。排查后發(fā)現(xiàn)~/.bash_history文件有幾十萬(wàn)行文件已超過(guò) 100MB并且在之前某次磁盤寫滿的情況下文件尾部出現(xiàn)了不完整的 NULL 字節(jié)。解決辦法分幾步。先備份原文件然后清理過(guò)大的歷史cp ~/.bash_history ~/.bash_history.bak接著用history -c清空當(dāng)前會(huì)話內(nèi)存然后重置文件 ~/.bash_history history -r這樣文件回到干凈狀態(tài)history的響應(yīng)速度也恢復(fù)了。要注意的是清空文件會(huì)讓所有歷史記錄永久丟失所以備份動(dòng)作格外重要。如果不想清空也可以用tail -n 5000 ~/.bash_history ~/.bash_history_new mv ~/.bash_history_new ~/.bash_history只保留最近 5000 條既瘦身又不至于全部丟光。這個(gè)案例也說(shuō)明一個(gè)問(wèn)題~/.bash_history本身是個(gè)普通文本文件會(huì)被各種異常情況破壞養(yǎng)成定期備份的習(xí)慣尤其是在重要服務(wù)器上非常必要。6. 面試考場(chǎng)上的 history 相關(guān)提問(wèn)與實(shí)戰(zhàn)場(chǎng)景6.1 面試官最常問(wèn)的幾個(gè)小點(diǎn)結(jié)合這兩年面 Linux 運(yùn)維崗和后臺(tái)開(kāi)發(fā)崗的情況history相關(guān)的問(wèn)題出現(xiàn)頻率相當(dāng)高。我整理了幾個(gè)高頻考點(diǎn)每個(gè)都能現(xiàn)場(chǎng)演示驗(yàn)證。第一個(gè)問(wèn)題通常是“怎么查看最近執(zhí)行的 100 條命令”。答案有兩個(gè)history 100或者h(yuǎn)istory | tail -100。前者是查看內(nèi)存列表最后 100 條后者是查看歷史文件的最后 100 行。注意區(qū)分“歷史記錄數(shù)量”和“顯示最近 N 條”面試官有時(shí)候會(huì)故意混淆這兩個(gè)表述。第二個(gè)問(wèn)題圍繞!!、!$、!string的區(qū)別。!!執(zhí)行上一條命令!$代表上一條命令的最后一個(gè)參數(shù)!string執(zhí)行最近一條以指定字符串開(kāi)頭的命令。其中!$的使用頻率不亞于!!尤其是這種場(chǎng)景mkdir /data/log cd !$先創(chuàng)建目錄然后立刻切到剛創(chuàng)建的目錄里不用重復(fù)輸入路徑。這個(gè)組合能直接提高日常操作效率。第三個(gè)問(wèn)題是“如何讓歷史記錄顯示時(shí)間戳”這個(gè)在第 3 章已經(jīng)講過(guò)了。說(shuō)出HISTTIMEFORMAT環(huán)境變量的配置方式這道題就能過(guò)關(guān)。第四個(gè)問(wèn)題是“如何不留痕跡地清空歷史記錄”。這里有兩種理解一種是想在當(dāng)前會(huì)話中快速清空用history -c另一種是讓某條命令不進(jìn)入歷史用空格開(kāi)頭 HISTCONTROLignorespace。在面試中建議把兩種都答出來(lái)展示思考的完整性。6.2 故障排查中的實(shí)際復(fù)盤案例再分享一個(gè)實(shí)際排障案例。有一回線上服務(wù)突然異常我登錄服務(wù)器排查時(shí)先用history拉出最近幾十條命令發(fā)現(xiàn)服務(wù)異常前有人執(zhí)行過(guò)一個(gè)/tmp/目錄下的腳本清理命令再配合HISTTIMEFORMAT顯示的時(shí)間戳確認(rèn)了清理腳本是在服務(wù)發(fā)布前 10 分鐘執(zhí)行的而腳本里正好有一條針對(duì)日志目錄的清除操作。整個(gè)定位過(guò)程只花了五分鐘而同樣的問(wèn)題如果靠猜可能需要多花一兩個(gè)小時(shí)。這類復(fù)盤的經(jīng)驗(yàn)可以總結(jié)為服務(wù)器上的history就是一個(gè)操作流水賬線上一旦出了問(wèn)題第一時(shí)間去看異常時(shí)間窗口前后的命令記錄往往能直接鎖定嫌疑操作。這也是很多公司要求運(yùn)維同學(xué)保留歷史記錄、配置時(shí)間戳的根本原因。實(shí)際工作中我還會(huì)在排查問(wèn)題前專門執(zhí)行一遍history | tail -50先看看自己最近在這臺(tái)機(jī)器上做過(guò)什么避免對(duì)著自己的操作筆錄做無(wú)頭排查。這個(gè)動(dòng)作看起來(lái)簡(jiǎn)單但它能有效避免“現(xiàn)場(chǎng)已經(jīng)被自己改了幾輪原始問(wèn)題狀態(tài)已經(jīng)丟失”這種尷尬。7. 寫在最后一些屬于我自己的使用心得history這個(gè)命令乍一看是個(gè)簡(jiǎn)單工具但如果把它的存儲(chǔ)機(jī)制、多終端交互邏輯和去重時(shí)間戳配置組合起來(lái)能發(fā)揮的作用遠(yuǎn)超“查看聊天記錄”這個(gè)表面功能。根據(jù)我的個(gè)人經(jīng)驗(yàn)初學(xué) Linux 的人最容易犯的錯(cuò)是把history只當(dāng)成“查看命令歷史的命令”而忽略了!系列展開(kāi)符和 CtrlR 這兩個(gè)能大幅提升輸入效率的功能。記住history最大的價(jià)值是“檢索”不是“查看”。同樣是找回一條舊命令用 CtrlR 增量搜索幾乎不需要思考效率遠(yuǎn)高于先把歷史列表翻出來(lái)再瞪著眼睛硬找。還有一點(diǎn)想特別提醒如果你在一臺(tái)長(zhǎng)期不重啟的服務(wù)器上工作~/.bash_history文件會(huì)隨著時(shí)間越積越大檢索速度會(huì)逐步下降。我習(xí)慣給每臺(tái)重要服務(wù)器的HISTSIZE和HISTFILESIZE設(shè)置一個(gè)合理上限并且每個(gè)月做一次人工備份。備份方式非常簡(jiǎn)單就是把這份文件同步到其他機(jī)器或者打包到備份目錄里成本幾乎為零真到了需要翻舊賬的那天這份備份能幫你省掉太多麻煩。history雖然是命令但它更像一面操作鏡子把你在終端上做過(guò)的每個(gè)動(dòng)作都記錄下來(lái)。用好了它是提效工具、是故障定位的索引、是面試的加分項(xiàng)用不好它就是泄露敏感信息的通道或者讓你在白忙中耗盡精力的隱形坑。希望這篇基于真實(shí)踩坑經(jīng)驗(yàn)整理的文章能幫你把這面鏡子擦得更亮一些。