vim和echo修改文件的区别

背景

最近研究filebeat的时候,发现每次修改文件后输出的是文件的全量内容,与自己期望的不太一样,然后又翻看了相关的文章,快速过了下官方文档。得出一个结论,filebeat默认应该是输出的文件增量内容才对,经群里小伙伴的提示才反应过来,问题是不是出在修改文件的方式?果不其然,我个人调试的时候使用的是vim修改文件新增内容的,换成echo的方式后,达到了期望的结果。那么为什么vim不行呢?

什么是inode?

每个文件有一个inode标识,操作系统通过inode的号码来识别不同的文件。unix/linux系统内部不使用文件名来识别文件,文件名只是inode号码便于识别的别称。表面上,用户通过文件名打开文件,而实际系统内部将这个过程分为三步:

  1. 首先找到这个文件名对应的inode号码
  2. 其次通过inode号码获取inode信息
  3. 最后根据inode信息,找到文件数据所在的block,读出数据

查看文件的inode信息可以使用下述命令:

1
2
3
4
5
6
7
8
9
(venvStudy) [root@node1 filebeat-8.5.2-linux-x86_64]# stat test.json
File: ‘test.json’
Size: 963 Blocks: 8 IO Block: 4096 regular file
Device: fd01h/64769d Inode: 1845136 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2022-11-14 21:28:48.542300958 +0800
Modify: 2022-11-14 21:28:48.542300958 +0800
Change: 2022-11-14 21:28:48.546301002 +0800
Birth: -

猜测使用vim应该是修改inode,而使用echo则不会。

验证

使用vim修改文件内容后,查看文件的inode如下:

1
2
3
4
5
6
7
8
9
10
11
(venvStudy) [root@node1 filebeat-8.5.2-linux-x86_64]# vim test.json
(venvStudy) [root@node1 filebeat-8.5.2-linux-x86_64]# stat test.json
File: ‘test.json’
Size: 882 Blocks: 8 IO Block: 4096 regular file
Device: fd01h/64769d Inode: 1845742 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2022-11-14 21:35:14.155696874 +0800
Modify: 2022-11-14 21:35:14.155696874 +0800
Change: 2022-11-14 21:35:14.167697004 +0800
Birth: -

而使用echo修改文件内容后,查看文件的inode如下:

1
2
3
4
5
6
7
8
9
10
11
(venvStudy) [root@node1 filebeat-8.5.2-linux-x86_64]# echo 'xxxxx' >> ./test.json
(venvStudy) [root@node1 filebeat-8.5.2-linux-x86_64]# stat test.json
File: ‘test.json’
Size: 963 Blocks: 8 IO Block: 4096 regular file
Device: fd01h/64769d Inode: 1845742 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2022-11-14 21:35:14.155696874 +0800
Modify: 2022-11-14 21:37:20.004064506 +0800
Change: 2022-11-14 21:37:20.004064506 +0800
Birth: -

确实发现使用vim的话,inode改变了。使用echo则inode保持不变。

调试

通过inotifywait监控一下文件的变化,该命令位于inotify-tools下,需要单独安装。
源码编译安装的涉及到的命令如下:

1
2
3
4
5
6
wget http://github.com/downloads/rvoicilas/inotify-tools/inotify-tools-3.14.tar.gz
tar zxvf inotify-tools-3.14.tar.gz
cd inotify-tools-3.14
./configure
make
make install

其他安装方式见官方文档:https://github.com/rvoicilas/inotify-tools/wiki#wiki-getting
参数说明:

  • -m:持续监视变化
  • -r:使用递归形式监视目录
  • -q:减少冗余信息,只打印出需要的信息
  • -e:指定要监视的事件列表
  • –timefmt:指定时间的输出格式
  • –format:指定文件变化的详细信息

当使用vim修改文件内容时,inotifywait的输出如下:

1
2
3
4
5
6
7
8
9
[root@node1 filebeat-8.5.2-linux-x86_64]# inotifywait -rm ./test.json
Setting up watches. Beware: since -r was given, this may take a while!
Watches established.
./test.json OPEN
./test.json ACCESS
./test.json CLOSE_NOWRITE,CLOSE
./test.json MOVE_SELF
./test.json ATTRIB
./test.json DELETE_SELF

发现最后有DELETE_SELF的操作,此时再修改文件内容时,已经无法监听到了,需要重新监听。
当使用echo修改文件内容时:

1
2
3
4
5
6
[root@node1 filebeat-8.5.2-linux-x86_64]# inotifywait -rm ./test.json
Setting up watches. Beware: since -r was given, this may take a while!
Watches established.
./test.json OPEN
./test.json MODIFY
./test.json CLOSE_WRITE,CLOSE

echo只是对文件进行了修改
另外可以监听整个目录的变化,能看到更多信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 使用vim修改发生的变化
[root@node1 filebeat-8.5.2-linux-x86_64]# inotifywait -rm ./
Setting up watches. Beware: since -r was given, this may take a while!
Watches established.
./ OPEN test.json
./ CREATE .test.json.swp
./ OPEN .test.json.swp
./ CREATE .test.json.swx
./ OPEN .test.json.swx
./ CLOSE_WRITE,CLOSE .test.json.swx
./ DELETE .test.json.swx
./ CLOSE_WRITE,CLOSE .test.json.swp
./ DELETE .test.json.swp
./ CREATE .test.json.swp
./ OPEN .test.json.swp
./ MODIFY .test.json.swp
./ ATTRIB .test.json.swp
./ CLOSE_NOWRITE,CLOSE test.json
./ OPEN test.json
./ ACCESS test.json
./ CLOSE_NOWRITE,CLOSE test.json
./ OPEN,ISDIR
./ CLOSE_NOWRITE,CLOSE,ISDIR
./ OPEN,ISDIR
./ CLOSE_NOWRITE,CLOSE,ISDIR


# 打开文件会看到上述信息, 修改内容并保存时输出下面的内容
./ CREATE 4913
./ OPEN 4913
./ ATTRIB 4913
./ CLOSE_WRITE,CLOSE 4913
./ DELETE 4913
./ MOVED_FROM test.json
./ MOVED_TO test.json~
./ MODIFY .test.json.swp
./ CREATE test.json
./ OPEN test.json
./ MODIFY test.json
./ CLOSE_WRITE,CLOSE test.json
./ ATTRIB test.json
./ MODIFY .test.json.swp
./ DELETE test.json~

发现保存的时候执行了MOVED_TO test.json~,并新建了一个test.json文件。

有没有什么方式使用vim但是也不会修改inode呢?
有两种方式:

  • 和文件权限有关:chmod o+w test.json

  • 修改vim设置,关闭其备份:set nobackup nowritebackup,关闭后保存时不会生成test.json~文件

    总结

  • vim修改是产生了新的文件,inode发送了改变,而echo不会。

  • vim保存时会产生带~后缀的文件,这个文件是保存时生成,正常保存该文件会被立即删除

  • 若文件其他用户有write权限(chmod o+w xxx),vim编辑时inode不会发生改变

  • 关闭vim备份时,inode信息也不会发生改变