|
想了十天十夜不知道写些什么,那就写写面试题吧。 / P8 g ]% `9 H9 I- q, k == 1 ==6 B* z, x* Q1 U8 W+ y 6 z6 _: R7 a2 O7 K 在面试应聘者的时候,我常常会问: 在 Linux 下,如何删除一个目录下的所有 log 文件? : U: H' i, f% H$ F! l 不知道是不是我人畜无害的围笑给了应聘者我很好应付的错觉 : I$ X M( y* b+ c7 \) m$ Y/ Y! g 以至于应聘者全都回答:rm *.log / u. t9 S/ S* v( s6 S 追问:该目录下可能有很多子目录(还可能是多级),如何把子目录里的 log 文件也删掉呢? 答:rm -r *.log 2 I5 I0 G7 r1 q& q" H+ i, V == 2 == 令我很意外的是,只有很少的应聘者能想到 find 命令。 2 d# n6 D1 W! J$ {% | 而且想到的人也很少有记得具体用法的。 $ @+ ]+ I" V" s2 r' X 目前为止只有一个应聘者能够给出完整的命令: 注:这里的两个斜杠都不是笔误。这里除了 -exec ...,也可以用 -delete,或者用管道结合 xargs 来完成;又或者 ls -r | grep 也行。 9 s+ v; t2 V/ A$ B* ~ 我觉得 find 应该不算一个很罕见的命令? 我们有一台共享开发机,因为大家都懒得删 log ,经常磁盘爆满,后来我们给它加了个 crontab: 注:".log*" 后面的 * 是考虑了 log rotate。 " E3 \0 ? o% s6 e 注意,这个命令没有用 rm ,而是使用重定向来清空文件,原因后面会讲。 . h O- p# ~! {8 q- l" y0 D 1 `' Z4 O+ P/ F/ t* k0 M! D3 p, F2 V == 3 == 6 q5 |3 M" I+ E* {7 v, G 基于清理磁盘空间这个场景,我还会继续问: 你有遇到过删了 log 文件,但是磁盘空间却没有释放的情况吗?! T6 [( x! p6 U' K3 Z8 U * ]9 E1 `; {+ P 有些候选人可能心里在想着:文件删了不就删了吗,还有什么磁盘空间没释放? 5 |- W- O: G5 |+ _" B" h 所以有时候我需要解释一下,是 df 命令看到的磁盘空间没有减少。 还有个候选人努力想了想,和我确认,是不是正好这个目录挂载的是其他磁盘,所以看起来当前磁盘空间没减少。(当然不是) 思路稍微开阔一点的候选人会想到:你个憨批莫不是删了个软链接吧?8 S; o" w9 ]# U6 z2 N0 p1 C # f% {. r0 e" L. W) S, \ 当然候选人的语气会比较友好。 : H& v8 s5 R: T 然后我会和候选人继续沟通: , ^$ |5 d6 u8 ^; R- V9 j% a2 [% ^ 你提到了软链接,那它和硬链接的区别是什么呢?) v' ~) B' F5 y& C. D$ E 有时候我怀疑这几个连续的问题问到候选人开始怀疑人生,因为有的候选人有点犹豫,觉得自己想说的其实是硬链接。 % D9 M# P* ^+ ~ 不过还是有几个候选人知道,软链接是一种文件类型,其内容是目标文件的路径;硬链接是 inode 的别名,同一个 inode 可以有多个链接,在 inode 里记录了硬链接的数量(引用计数)。- F# T0 A2 v6 R# s ; T# g. Y" z* R1 a1 o) o3 G 比如这样: 创建一个空文件,看下inode和链接数: 创建一个软链接,再看看文件大小:9 \' d! Z; N: C N# c2 v) b $ ls -l b.txt #大小5字节lrwxrwxrwx ... 5 ... b.txt -> a.txt& L& T X& A6 ] b& s1 K0 c6 } $ readlink b.txt #文件内容a.txt 创建一个硬链接,看下inode和链接数 $ ls -l c.txt #大小0字节,和a一样lrwxrwxrwx ... 0 ... c.txt . E$ n n' s( h 4 w8 Z6 k# c h& K == 4 ==$ b' z* b* S0 d* { 但实际生产上,遇到 “删了文件、但空间不释放” 通常和软/硬链接没有什么关系。 + P% b$ h5 p; ^! E 1 m* |7 x8 C* b2 x4 e 实(cai)战(keng)经验比较丰富的候选人会知道,这更可能是因为文件正被另一个进程打开。 比如在终端 1 打开 a.txt: 然后在终端 2 可以看到该文件被 Python 打开:
删掉 a.txt,再查看 python 打开的文件列表: 注:0、1、2、3 是内核的 fd 编号。0=stdin, 1=stdout, 2=stder。 可以看到,a.txt 被标记为已删除,但因为进程还开着它,可能会访问文件的内容,所以内核会等到进程关闭该文件(或进程退出后)才在磁盘上移除这个文件。 == 5 == 在面试中通常没有机会再问下去了,但实践中往往问题还没解决。 比如前述共享开发机,就曾遇到了用 df 看磁盘空间800G已满,但用 du 查看,所有文件却只占用了 500G的情况。 那么: 1. 如何才能知道现在系统中有哪些文件已删除、但是仍被占用呢?
发现是有大量已经被删除、但仍被某些进程打开的 nohup.out 。4 Q! A, R7 d( P6 q 2. 坑是找到了,该怎么填呢? 由于这是开发机,很简单,把进程杀掉就好了,进程退出时,内核会负责关闭文件,然后清理占用的空间。 ( v2 Z: \2 a9 L" u 但如果是线上服务呢? 9 V7 k; v6 H) k4 s Linux下有一个 package 叫 logrotate,像 nginx 这些服务就是使用它来做日志切割/轮转的。 但 nginx 是在后台持续运行的,不能为了切个日志就停止服务,所以它们是这样约定的:
注:为什么是用 SIGHUP 而不是其他信号,以后可能会另开一篇讲讲。 + R% z: Q) ~. H8 n" [ 这样 logrotate 出来的日志,就可以放心删除了。" x4 H1 A& ~: F5 I; b/ v 对于不支持类似逻辑的服务怎么办呢? 重启大法。 如果只是想清空这个文件,可以这样(以前面python为例): 这样文件是清空了,适用于 append only 的日志文件,但对于其他场景可能存在一定风险。$ @) O1 z8 {) w5 U$ b, b. b1 ^8 M W3 Y" C6 g2 }" S- X* B 要是不怕背 P0 的话,还可以这么作死: 注:ftruncate只是清空文件,如果想关闭文件,可以结合 dup、dup2、open和close来搞事,不细说了。 7 J( {6 X# M1 P: [; l% @ 9 j% j8 g+ T5 U6 R- W == 6 == 3 j" ^; U; Q5 e1 t 看到这里你应该明白了为什么前面那个 find 命令不直接用 rm 了吧? % I) I; t) M( V3 p3 { 照例总结下:
|
| 顶一下 |
微信公众号
手机版