你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

在 Linux 下,如何删除一个目录下的所有 log 文件?

[复制链接]
gaosmile 发布时间:2020-7-9 13:00
想了十天十夜不知道写些什么,那就写写面试题吧。

! I' m2 L' Z* y$ a( B7 O8 d6 u

/ P8 g  ]% `9 H9 I- q, k
== 1 ==6 B* z, x* Q1 U8 W+ y
6 z6 _: R7 a2 O7 K
在面试应聘者的时候,我常常会问:

' }3 c1 f( L" X
在 Linux 下,如何删除一个目录下的所有 log 文件?
: U: H' i, f% H$ F! l
不知道是不是我人畜无害的围笑给了应聘者我很好应付的错觉
: I$ X  M( y* b+ c7 \) m$ Y/ Y! g

8 |8 k* `$ P& ], o
以至于应聘者全都回答:rm *.log
/ u. t9 S/ S* v( s6 S
追问:该目录下可能有很多子目录(还可能是多级),如何把子目录里的 log 文件也删掉呢?

1 Y# [; V: [( d6 g2 w7 b
答:rm -r *.log

# }+ k5 p; B6 f) P- t/ ?( V; r# |
2 I5 I0 G7 r1 q& q" H+ i, V


& J" z* Z1 h8 D9 ?% \  d
== 2 ==
& o; B# Z2 V4 Q" Y! y) P; x

, H2 q; ~% F4 j1 n$ R3 h
令我很意外的是,只有很少的应聘者能想到 find 命令。
2 d# n6 D1 W! J$ {% |
而且想到的人也很少有记得具体用法的。
$ @+ ]+ I" V" s2 r' X

/ U9 O$ j# A( ~& v+ @% L
目前为止只有一个应聘者能够给出完整的命令:

  • 0 N. D; e: }6 G0 F) q% b) x
find -name \*.log -exec rm -f {} \;
注:这里的两个斜杠都不是笔误。这里除了 -exec ...,也可以用 -delete,或者用管道结合 xargs 来完成;又或者 ls -r | grep 也行。
9 s+ v; t2 V/ A$ B* ~
我觉得 find 应该不算一个很罕见的命令?

+ D% a6 b" w( ]( C/ D
我们有一台共享开发机,因为大家都懒得删 log ,经常磁盘爆满,后来我们给它加了个 crontab:

  • 9 a7 V3 `# V0 y
0 4 * * * find /home/ -type f -name "*.log*" -size +100M -exec bash -c "echo -n > '{}'" \;
注:".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
基于清理磁盘空间这个场景,我还会继续问:
8 I! y0 N4 M- I9 i: c

$ Q  g4 _2 @, \+ P4 }* r! p
你有遇到过删了 log 文件,但是磁盘空间却没有释放的情况吗?! T6 [( x! p6 U' K3 Z8 U
* ]9 E1 `; {+ P
有些候选人可能心里在想着:文件删了不就删了吗,还有什么磁盘空间没释放?
5 |- W- O: G5 |+ _" B" h

& O( k) a, k5 ?- ~. r" A9 z1 s
所以有时候我需要解释一下,是 df 命令看到的磁盘空间没有减少。

7 m% L$ e- l: R$ [  F0 n5 q# {
还有个候选人努力想了想,和我确认,是不是正好这个目录挂载的是其他磁盘,所以看起来当前磁盘空间没减少。(当然不是)

) C0 Z# [  Y3 {5 R
思路稍微开阔一点的候选人会想到:你个憨批莫不是删了个软链接吧?8 S; o" w9 ]# U6 z2 N0 p1 C

3 c1 Q0 {# n3 C9 M# C. R
# f% {. r0 e" L. W) S, \
当然候选人的语气会比较友好。
: H& v8 s5 R: T
然后我会和候选人继续沟通:
: W5 |' D6 X. ?8 k# X9 G
, ^$ |5 d6 u8 ^; R- V9 j% a2 [% ^
你提到了软链接,那它和硬链接的区别是什么呢?) v' ~) B' F5 y& C. D$ E

: Z0 Z5 l+ E1 G! g- ~  k
有时候我怀疑这几个连续的问题问到候选人开始怀疑人生,因为有的候选人有点犹豫,觉得自己想说的其实是硬链接。
% D9 M# P* ^+ ~

. T4 w- i* N8 o$ C& [
不过还是有几个候选人知道,软链接是一种文件类型,其内容是目标文件的路径;硬链接是 inode 的别名,同一个 inode 可以有多个链接,在 inode 里记录了硬链接的数量(引用计数)。- F# T0 A2 v6 R# s
; T# g. Y" z* R1 a1 o) o3 G
比如这样:

9 j( N$ y8 L& K( D" |
创建一个空文件,看下inode和链接数:

  • ' j" L1 D. q) M) ^
$ touch a.txt #创建一个空文件$ stat -c 'inode %i, links %h' a.txtinode 12058942, links 1
创建一个软链接,再看看文件大小:9 \' d! Z; N: C  N# c2 v) b

  • & I* H; B" H* J1 D( _9 s* M
$ ln -s a.txt b.txt #软链接$ stat -c 'inode %i, links %h' b.txtinode 12058978, links 1
, X2 D* K9 K* Q  a; R+ s$ ls -l b.txt #大小5字节lrwxrwxrwx ... 5 ... b.txt -> a.txt& L& T  X& A6 ]  b& s1 K0 c6 }
$ readlink b.txt #文件内容a.txt

, v0 }5 d  Q* N+ h. N% g
创建一个硬链接,看下inode和链接数

  • 5 d- f# C4 c3 ^8 I/ j
$ ln a.txt c.txt #硬链接,inode不变,链接数变成2$ stat -c 'inode %i, links %h' c.txtinode 12058942, links 2! Y/ i- N  t% j8 @5 }- m
$ 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* {

3 O! V+ j5 R$ I0 ]4 S& Y2 ^: J6 |# S
但实际生产上,遇到 “删了文件、但空间不释放” 通常和软/硬链接没有什么关系。
+ P% b$ h5 p; ^! E
1 m* |7 x8 C* b2 x4 e
实(cai)战(keng)经验比较丰富的候选人会知道,这更可能是因为文件正被另一个进程打开。

# {( E6 ~! J- D' T" Z
比如在终端 1 打开 a.txt:

  • % ^' O5 ~- X, Z, @* b  W$ M
$ python>>> f = open("a.txt")
然后在终端 2 可以看到该文件被 Python 打开:
  • 1 G5 w8 Z" U% Z
$ lsof a.txtCOMMAND  PID ...     NODE NAMEpython  2390 ... 12058942 a.txt
删掉 a.txt,再查看 python 打开的文件列表:

  • ) L9 o7 Y; j# v. T2 o* z7 I
$ rm a.txt$ ls -l /proc/2390/fdlrwx------ 1 user ... 00:04 0 -> /dev/pts/5lrwx------ 1 user ... 00:04 1 -> /dev/pts/5lrwx------ 1 user ... 00:04 2 -> /dev/pts/5lr-x------ 1 user ... 00:04 3 -> /tmp/a.txt (deleted)
注:0、1、2、3 是内核的 fd 编号。0=stdin, 1=stdout, 2=stder。

* |9 n, O1 v7 o* Y  x+ B  V; A
可以看到,a.txt  被标记为已删除,但因为进程还开着它,可能会访问文件的内容,所以内核会等到进程关闭该文件(或进程退出后)才在磁盘上移除这个文件。

% v' [( s9 V1 r# C/ _2 ]2 h


4 c* e6 Q% \5 p  e, a; U
== 5 ==

0 R6 ?' g) d# c* _
在面试中通常没有机会再问下去了,但实践中往往问题还没解决。

4 T4 n  A+ `# K2 i% ^6 L
比如前述共享开发机,就曾遇到了用 df 看磁盘空间800G已满,但用 du 查看,所有文件却只占用了 500G的情况。

% L' s, H- V* }# Q' q/ m
那么:
0 Q3 |0 S4 p1 ^; ~% h

  P- D# r7 O4 n( ^1 y
1. 如何才能知道现在系统中有哪些文件已删除、但是仍被占用呢?
  • 2 |1 A7 Q0 g! v; [: i' N0 U
$ sudo lsof | grep deletedCOMMAND   PID  …  NAMEmain   893246  …  /../nohup.out (deleted)...
发现是有大量已经被删除、但仍被某些进程打开的 nohup.out 。4 Q! A, R7 d( P6 q

  O" i4 E# o* W
2. 坑是找到了,该怎么填呢?

2 i/ [; `0 D) x* Q
由于这是开发机,很简单,把进程杀掉就好了,进程退出时,内核会负责关闭文件,然后清理占用的空间。
( v2 Z: \2 a9 L" u
但如果是线上服务呢?
9 V7 k; v6 H) k4 s
Linux下有一个 package 叫 logrotate,像 nginx 这些服务就是使用它来做日志切割/轮转的。

3 X8 v6 B" b: K( t
但 nginx 是在后台持续运行的,不能为了切个日志就停止服务,所以它们是这样约定的:
  • logrotate 执行 rename 系统调用(相当于 mv 命令)重命名日志文件;
  • 由于 inode 不变,这时 nginx 会继续写入重命名后的日志文件;
  • logrotate 给 nginx 发送一个 SIGHUP 信号;
  • nginx 在收到信号后会关闭当前文件,并重新打开日志文件(即创建了新的日志文件)。

    2 T' o- D% i/ R& M; c

2 K" j) V, v7 H( F' h% t
注:为什么是用 SIGHUP 而不是其他信号,以后可能会另开一篇讲讲。
+ R% z: Q) ~. H8 n" [
这样 logrotate 出来的日志,就可以放心删除了。" x4 H1 A& ~: F5 I; b/ v

, K% r/ ]% A6 p+ S5 [) ~0 g9 h
对于不支持类似逻辑的服务怎么办呢?

# v  G7 o' @, x  s/ A  w( L
重启大法。

6 f0 |! k; H' B3 [' E! o
如果只是想清空这个文件,可以这样(以前面python为例):

  • 4 d( B9 t$ c* W2 q+ k
$ echo -n > /proc/2390/fd/3
这样文件是清空了,适用于 append only 的日志文件,但对于其他场景可能存在一定风险。$ @) O1 z8 {) w5 U$ b, b. b1 ^8 M
  W3 Y" C6 g2 }" S- X* B
要是不怕背 P0 的话,还可以这么作死:

  • + }0 h( D6 g5 N3 a
$ sudo gdb(gdb) attach $PID(gdb) call ftruncate(3, 0) #按需修改fd$1 = 0
注:ftruncate只是清空文件,如果想关闭文件,可以结合 dup、dup2、open和close来搞事,不细说了。
* a2 i, `/ z1 m5 z2 x0 D% O- P5 u

5 c- f* W8 g0 p  }
7 J( {6 X# M1 P: [; l% @

9 j% j8 g+ T5 U6 R- W
== 6 ==
  k0 U" T3 ^* S8 b
3 j" ^; U; Q5 e1 t
看到这里你应该明白了为什么前面那个 find 命令不直接用 rm 了吧?
% I) I; t) M( V3 p3 {
照例总结下:
  • 可以用 find 查找文件
  • 软链接存的是路径,硬链接共享inode
  • 删除被进程打开的文件,磁盘空间不会释放
  • lsof 很好用(不只是看文件的占用)

    2 Q$ S7 {* S# V7 X5 i
4 N7 r4 I4 d! V' y; U4 y
赞 收藏 评论1 发布时间:2020-7-9 13:00

举报

1个回答
李康1202 回答时间:2020-7-9 14:44:03
顶一下
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版