想了十天十夜不知道寫些什麼,那就寫寫面試題吧。node
在面試應聘者的時候,我經常會問:python
在 Linux 下,如何刪除一個目錄下的全部 log 文件?nginx
不知道是否是我人畜無害的圍笑給了應聘者我很好應付的錯覺 面試
以致於應聘者全都回答:rm *.log
bash
追問:該目錄下可能有不少子目錄,如何把子目錄裏的 log 文件也刪掉呢?spa
答:rm -r *.log
3d
令我很意外的是,真的只有不多的應聘者能想到 find 命令。日誌
並且想到的人也不多有記得具體用法的。code
目前爲止只有一個應聘者可以給出完整的命令:blog
find -name \*.log -exec rm -f {} \;
注:這裏的兩個斜槓都不是筆誤。
我以爲 find 應該不算一個很罕見的命令?
咱們有一臺共享開發機,由於你們都懶得刪 log ,常常磁盤爆滿,後來咱們給它加了個 crontab:
0 4 * * * find /home/ -type f -name "*.log*" -size +100M -exec bash -c "echo -n > '{}'" \;
注:".log*" 後面的 * 是考慮了 log rotate。
注意,這個命令沒有用 rm ,而是使用重定向來清空文件,緣由後面會講。
基於清理磁盤空間這個場景,我還會繼續問:
你有遇到過刪了 log 文件,可是磁盤空間卻沒有釋放的狀況嗎?
有些候選人可能內心在想着:文件刪了不就刪了嗎,還有什麼磁盤空間沒釋放?
因此有時候我須要解釋一下,是 df 命令看到的磁盤空間沒有減小。
還有個候選人努力想了想,和我確認,是否是正好這個目錄掛載的是其餘磁盤,因此看起來當前磁盤空間沒減小。(固然不是)
思路稍微開闊一點的候選人會想到:你個憨批莫不是刪了個軟連接吧?
固然候選人的語氣會比較友好。
而後我會和候選人繼續溝通:
你提到了軟連接,那它和硬連接的區別是什麼呢?
有時候我懷疑這幾個連續的問題問到候選人開始懷疑人生,由於有的候選人有點猶豫,以爲本身想說的實際上是硬連接。
不過仍是有幾個候選人知道,軟連接是一種文件類型,其內容是目標文件的路徑;硬連接是 inode 的別名,同一個 inode 能夠有多個連接,在 inode 裏記錄了硬連接的數量(引用計數)。
好比這樣:
建立一個空文件,看下inode和連接數:
$ touch a.txt #建立一個空文件 $ stat -c 'inode %i, links %h' a.txt inode 12058942, links 1
建立一個軟連接,再看看文件大小:
$ ln -s a.txt b.txt #軟連接 $ stat -c 'inode %i, links %h' b.txt inode 12058978, links 1 $ ls -l b.txt #大小5字節 lrwxrwxrwx ... 5 ... b.txt -> a.txt $ readlink b.txt #文件內容 a.txt
建立一個硬連接,看下inode和連接數
$ ln a.txt c.txt #硬連接,inode不變,連接數變成2 $ stat -c 'inode %i, links %h' c.txt inode 12058942, links 2 $ ls -l c.txt #大小0字節,和a同樣 lrwxrwxrwx ... 0 ... c.txt
但實際生產上,遇到 「刪了log文件、但空間不釋放」 一般和軟/硬連接沒有什麼關係。
實戰經驗比較豐富的候選人會知道,這每每是由於 log 文件正被另外一個進程打開。
好比在終端 1 打開 a.txt:
$ python >>> f = open("a.txt")
而後在終端 2 能夠看到該文件被 Python 打開:
$ lsof a.txt COMMAND PID ... NODE NAME python 2390 ... 12058942 a.txt
刪掉 a.txt,再查看 python 打開的文件列表:
$ rm a.txt $ ls -l /proc/2390/fd lrwx------ 1 user ... 00:04 0 -> /dev/pts/5 lrwx------ 1 user ... 00:04 1 -> /dev/pts/5 lrwx------ 1 user ... 00:04 2 -> /dev/pts/5 lr-x------ 1 user ... 00:04 3 -> /tmp/a.txt (deleted)
注:0、一、二、3 是內核的 fd 編號。0=stdin, 1=stdout, 2=stder。
能夠看到,a.txt 被標記爲已刪除,但由於進程還開着它,可能會訪問文件的內容,因此內核會等到進程關閉該文件(或進程退出後)纔在磁盤上移除這個文件。
在面試中一般沒有機會再問下去了,但實踐中每每問題還沒解決。
好比前述共享開發機,就曾遇到了磁盤空間共800G,但用 du 命令查看,全部文件只佔用了 500G的狀況。
那麼:
1. 如何才能知道如今系統中有哪些文件已刪除、可是仍被佔用呢?
$ sudo lsof | grep deleted COMMAND PID … NAME main 893246 … /../nohup.out (deleted) ...
發現是有大量已經被刪除、但仍被某些進程打開的 nohup.out 。
2. 坑是找到了,該怎麼填呢?
因爲這是開發機,很簡單,把進程殺掉就行了,進程退出時,內核會負責關閉文件,而後清理佔用的空間。
但若是是線上服務呢?
Linux下有一個 package 叫 logrotate,像 nginx 這些服務就是使用它來作日誌切割/輪轉的。
但 nginx 是在後臺持續運行的,不能爲了切個日誌就中止服務,因此它們是這樣約定的:
注:爲何是用 SIGHUP 而不是其餘信號,之後可能會另開一篇講講。
這樣 logrotate 出來的日誌,就能夠放心刪除了。
對於不支持相似邏輯的服務怎麼辦呢?
重啓大法。
若是不怕背 P0 的話,還能夠這麼做死:
$ sudo gdb (gdb) attach $PID (gdb) call ftruncate(3, 0) #按需修改fd $1 = 0
注:看起來文件是清空了,但可能存在其餘坑,後果自負。ftruncate只是清空文件,若是想關閉文件,能夠結合 dup、dup二、open和close來搞事,不細說了。
看到這裏你應該明白了爲何前面那個 find 命令不直接用 rm 了吧?
照例總結下:
還想知道其餘有意思的面試題嗎?
不如投個簡從來親身體驗下:
~ 投遞連接 ~
投放研發工程師(上海)
https://job.toutiao.com/s/J8D...
高級廣告研發工程師(北京)
https://job.toutiao.com/s/J8D...