Linux:使用vim编辑文件为什么会影响目录的mtime

一个有趣的现象

最近在调试一个问题时,发现了一个有趣的现象:touch一个存在的文件,文件的mtime发生了更新,文件所在目录的mtime不会更新;而使用vim编辑这个文件后再保存,文件和文件所在目录的mtime都会被更新。为什么会这样呢?本文将解释一下这种现象的成因。

背景知识

使用ls -al命令查看文件或目录时,在倒数第二列我们可以看到一个时间,它是文件最近的修改时间modify time(mtime)。而使用stat查看文件信息时,除了可以看到有mtime,还有access time(atime)、change time(ctime)和birth time(btime/crtime):

$ ls -al
total 8
drwxr-xr-x 2 imred imred 4096 Jul 17 22:19 .
drwxr-xr-x 3 imred imred 4096 Jul 17 22:19 ..
-rw-r--r-- 1 imred imred    0 Jul 17 22:19 abc.txt$ stat abc.txtFile: abc.txtSize: 0               Blocks: 0          IO Block: 4096   regular empty file
Device: 820h/2080d      Inode: 5682        Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/   imred)   Gid: ( 1000/   imred)
Access: 2024-07-17 22:19:20.927884988 +0800
Modify: 2024-07-17 22:19:20.927884988 +0800
Change: 2024-07-17 22:19:20.927884988 +0800Birth: 2024-07-17 22:19:20.927884988 +0800

使用man 7 inode可以得到关于这些时间的详细定义:

Last access timestamp (atime)stat.st_atime; statx.stx_atimeThis is the file's last access timestamp. It is changed by file accesses, for example, by execve(2), mknod(2), pipe(2), utime(2), and read(2) (of more than zero bytes). Other interfaces, such as mmap(2), may or may not update the atime timestampSome filesystem types allow mounting in such a way that file and/or directory accesses do not cause an update of the atime timestamp. (See noatime, nodiratime, and relatime in mount(8), and related information in mount(2).) In addition, the atime timestamp is not updated if a file is opened with the O_NOATIME flag; see open(2).File creation (birth) timestamp (btime)(not returned in the stat structure); statx.stx_btimeThe file's creation timestamp. This is set on file creation and not changed subsequently.The btime timestamp was not historically present on UNIX systems and is not currently supported by most Linux filesystems.Last modification timestamp (mtime)stat.st_mtime; statx.stx_mtimeThis is the file's last modification timestamp. It is changed by file modifications, for example, by mknod(2), truncate(2), utime(2), and write(2) (of more than zero bytes). Moreover, the mtime timestamp of a directory is changed by the creation or deletion of files in that directory. The mtime timestamp is not changed for changes in owner, group, hard link count, or mode.Last status change timestamp (ctime)stat.st_ctime; statx.stx_ctimeThis is the file's last status change timestamp. It is changed by writing or by setting inode information (i.e., owner, group, link count, mode, etc.).

我们在意的是mtime,对于文件来说,它在文件内容被修改时会得到更新,而目录的mtime更新则发生在当目录中的文件创建或删除时。当文件的权限信息等元信息被修改时,mtime并不会更新,而是会更新ctime

成因探讨

test目录下有一个名为abc.txt的文件,我们先看一下其信息:

$ stat . | grep -E "Modify|Birth|Inode"
Device: 820h/2080d      Inode: 4700        Links: 2
Modify: 2024-07-17 22:58:14.387883267 +0800Birth: 2024-07-17 22:19:06.287885009 +0800$ stat abc.txt | grep -E "Modify|Birth|Inode"
Device: 820h/2080d      Inode: 5682        Links: 1
Modify: 2024-07-17 22:19:20.927884988 +0800Birth: 2024-07-17 22:19:20.927884988 +0800

testmtime22:58:14abc.txtmtime22:19:20

使用touch更新abc.txtmtime后,再次查看:

$ touch abc.txt$ stat . | grep -E "Modify|Birth|Inode"
Device: 820h/2080d      Inode: 4700        Links: 2
Modify: 2024-07-17 22:58:14.387883267 +0800Birth: 2024-07-17 22:19:06.287885009 +0800$ stat abc.txt | grep -E "Modify|Birth|Inode"
Device: 820h/2080d      Inode: 5682        Links: 1
Modify: 2024-07-17 23:06:50.407883335 +0800Birth: 2024-07-17 22:19:20.927884988 +0800

testmtime仍然为22:58:14abc.txtmtime则被更新为23:06:50

使用vim编辑abc.txt后再次查看:

$ vim abc.txt$ stat . | grep -E "Modify|Birth|Inode"
Device: 820h/2080d      Inode: 4700        Links: 2
Modify: 2024-07-17 23:09:48.437882556 +0800Birth: 2024-07-17 22:19:06.287885009 +0800$ stat abc.txt | grep -E "Modify|Birth|Inode"
Device: 820h/2080d      Inode: 5732        Links: 1
Modify: 2024-07-17 23:09:48.417882556 +0800Birth: 2024-07-17 23:09:48.417882556 +0800

testabc.txtmtime都被更新为23:09:48

为什么使用touch和使用vim会有这种差异呢?难道是因为touch并没有真的改变文件内容导致的?那我们使用echo命令来编辑abc.txt试试:

$ echo xxx > abc.txt$ stat . | grep -E "Modify|Birth|Inode"
Device: 820h/2080d      Inode: 4700        Links: 2
Modify: 2024-07-17 23:09:48.437882556 +0800Birth: 2024-07-17 22:19:06.287885009 +0800$ stat abc.txt | grep -E "Modify|Birth|Inode"
Device: 820h/2080d      Inode: 5732        Links: 1
Modify: 2024-07-17 23:19:02.617882317 +0800Birth: 2024-07-17 23:09:48.417882556 +0800

touch一样,只有abc.txtmtime更新了,所以文件内容是否发生了实质性修改这个因素并不会影响结果,那vim编辑文件时和echo编辑文件时到底有什么差异?

如果你观察够仔细,会发现我在过滤stat输出时,把Inodebtime也打印出来了。对比一下前后几次stat命令的输出,我们会看到,在使用vim编辑abc.txt后,其Inode5682变成了5732btime22:19:20变成了23:09:48。换言之,使用vim编辑后的文件已经不是原来那个文件了。那么期间在test目录下必定创建了新的abc.txt,因此test目录的mtime更新也就是理所应当的了。

那么使用vim编辑一个文件时,在文件系统中究竟发生了什么呢?我们可以使用iwatch命令来研究这个问题。使用iwatch监听test目录,同时使用vim修改abc.txt,查看iwatch的输出:

$ iwatch . -e all_events
[17/Jul/2024 23:31:58] IN_CREATE ./.abc.txt.swp
[17/Jul/2024 23:31:58] IN_CREATE ./.abc.txt.swx
[17/Jul/2024 23:31:58] IN_CLOSE_WRITE ./.abc.txt.swx
[17/Jul/2024 23:31:58] IN_DELETE ./.abc.txt.swx
[17/Jul/2024 23:31:58] * ./.abc.txt.swx is deleted
[17/Jul/2024 23:31:58] IN_CLOSE_WRITE ./.abc.txt.swp
[17/Jul/2024 23:31:58] * ./.abc.txt.swp is closed
[17/Jul/2024 23:31:58] IN_DELETE ./.abc.txt.swp
[17/Jul/2024 23:31:58] * ./.abc.txt.swp is deleted
[17/Jul/2024 23:31:58] IN_CREATE ./.abc.txt.swp
[17/Jul/2024 23:32:02] IN_CREATE ./4913
[17/Jul/2024 23:32:02] IN_CLOSE_WRITE ./4913
[17/Jul/2024 23:32:02] IN_DELETE ./4913
[17/Jul/2024 23:32:02] * ./4913 is deleted
[17/Jul/2024 23:32:02] IN_MOVED_FROM ./abc.txt
[17/Jul/2024 23:32:02] IN_MOVED_TO ./abc.txt~
[17/Jul/2024 23:32:02] * ./abc.txt is moved to ./abc.txt~
[17/Jul/2024 23:32:02] IN_CREATE ./abc.txt
[17/Jul/2024 23:32:02] IN_CLOSE_WRITE ./abc.txt
[17/Jul/2024 23:32:02] * ./abc.txt is closed
[17/Jul/2024 23:32:02] IN_DELETE ./abc.txt~
[17/Jul/2024 23:32:02] * ./abc.txt~ is deleted
[17/Jul/2024 23:32:02] IN_CLOSE_WRITE ./.abc.txt.swp
[17/Jul/2024 23:32:02] IN_DELETE ./.abc.txt.swp
[17/Jul/2024 23:32:02] * ./.abc.txt.swp is deleted

你会发现,vim编辑文件时绝非打开、读取、修改、写入这样的流程,而是会创建多个临时文件。原始的abc.txt文件会被重命名为abc.txt~,然后创建新的abc.txt,写入修改后的内容。如果整个过程中没有发生错误,所有的临时文件最终都会删除,只剩下一个abc.txt。因为涉及到在目录中创建和删除文件的操作,mtime被更新也就理所当然了,这也就解释了文章开头描述的有趣现象。

补充信息

  1. .abc.txt.swp有什么作用?

主要有两个作用,一个是用于存储那些尚未写入磁盘的变更,防止vim崩溃后丢失数据;另一个是为了避免多个vim实例编辑同一个文件,当你使用多个vim实例编辑同一个文件时,你会得到类似这样的警告:

E325: ATTENTION
Found a swap file by the name ".abc.txt.swp"
...

参考链接:https://vi.stackexchange.com/questions/177/what-is-the-purpose-of-swap-files

  1. abc.txt~有什么作用?

这个文件是用来备份原始文件数据的,如果vim直接编辑原始文件,编辑过程中又发生了错误,没有这个备份文件的话,原始文件数据可能就丢失了。

参考链接:https://stackoverflow.com/questions/607435/why-does-vim-save-files-with-a-extension

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/874149.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kotlin中常见的创建协程的方式

以下是kotlin开发中一些最常见的创建协程的方式: 1. 使用CoroutineScope.launch 这是最常见的启动协程的方式,通常用于不需要返回结果的协程。它返回一个Job对象,可以用来管理协程的生命周期。 val scope CoroutineScope(Dispatchers.Def…

未来已来:生成式 AI 在对话系统与自主代理中的探索

🍎个人博客:个人主页 🏆个人专栏:日常聊聊 ⛳️ 功不唐捐,玉汝于成 目录 前言 正文 一、整体介绍 对话系统(Chat) 自主代理(Agent) 二、技术对比 技术差异 优…

安装anaconda后jupyter notebook打不开 闪退

首先,通过清华源安装了最新的anaconda(安装在了D盘) 尝试打开jupyter,发现小黑框1s后自己关了,根本不打开浏览器 之后尝试按照这个做了一遍https://blog.csdn.net/gary101818/article/details/123560304还是不行。。…

Nagios高频面试题及参考答案(2万字长文)

目录 什么是Nagios?它的主要功能是什么? Nagios可以监控哪些类型的资源? 描述Nagios的架构 Nagios如何处理高可用性? 解释Nagios中的“被动检查”和“主动检查” Nagios中有哪些主要的服务状态? Nagios配置文件的结构是什么样的? 描述Nagios的核心组件 如何在Na…

【BUG】已解决:TypeError: Descriptors cannot not be created directly.

已解决:TypeError: Descriptors cannot not be created directly. 目录 已解决:TypeError: Descriptors cannot not be created directly. 【常见模块错误】 【错误原因】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来…

创建和管理大量的数据对象:ScriptableObject

一、创建一个继承自ScriptableObject,名为ItemData的类 1、ItemData.cs using UnityEngine;[CreateAssetMenu(menuName "Items/Item")] public class ItemData : ScriptableObject {public string description;public Sprite thumbnail;public GameObj…

数据挖掘-分类和预测

来自🥬🐶程序员 Truraly | 田园 的博客,最新文章首发于:田园幻想乡 | 原文链接 | github (欢迎关注) 文章目录 概念KNN 算法决策树ID3 算法缺点 C4.5 算法CART 算法 贝叶斯算法朴素贝叶斯算法贝叶斯信念网络…

如何做好结构化逻辑分析:分析之万能公式

有人问:我看了很多书,可是一到分析问题和解决问题时,还是不知如何下手。你能给我一个万能框架吗?这样我遇到问题就可以马上找到思路、直接套用,再也不用让大脑去神游和不知所措了。 我想了想,总结出了这个…

突破•指针二

听说这是目录哦 复习review❤️野指针🫧assert断言🫧assert的神奇之处 指针的使用和传址调用🫧数组名的理解🫧理解整个数组和数组首元素地址的区别 使用指针访问数组🫧一维数组传参的本质🫧二级指针&#x…

2-41 基于matlab的小车倒立摆系统的控制及GUI动画演示

基于matlab的小车倒立摆系统的控制及GUI动画演示。输入小车及倒立摆的初始参数,位置参数,对仿真时间和步长进行设置,通过LQR计算K值,进行角度、角速度、位置、速度仿真及曲线输出,程序已调通,可直接运行。 …

Linux设置开机启动Nginx

设置开机启动项 systemctl enable nginx 这个命令会创建一个符号链接到/etc/systemd/system/目录下的multi-user.target.wants/目录,从而确保Nginx在系统启动时自动运行。 查看Nginx是否已设置开机启动项 systemctl list-unit-files | grep nginx 删除开机启动 …

数据无忧:2024年高效硬盘数据恢复解决方法

在这个数字化时代,数据已成为我们生活与工作中不可或缺的一部分。手机或者电脑不够存储数据的时候我们最常用的就是采购硬盘来存储。以备不时之需我们来学习一下硬盘数据恢复的一些技巧吧。 1.福、昕数据恢复 这工具是一款简单小巧的数据恢复工具。下载安装在一分…

文心一言 VS 讯飞星火 VS chatgpt (307)-- 算法导论22.2 5题

五、证明:在广度优先搜索算法里,赋给结点 u 的 u.d 值与结点在邻接链表里出现的次序无关。使用图 22-3 作为例子,证明:BFS 所计算出的广度优先树可以因邻接链表中的次序不同而不同。如果要写代码,请用go语言。 文心一…

51单片机(STC8H8K64U/STC8051U34K64)_RA8889驱动TFT大屏_I2C_HW参考代码(v1.3) 硬件I2C方式

本篇介绍单片机使用硬件I2C方式控制RA8889驱动彩屏。 提供STC8H8K64U和STC8051U34K64的参考代码。 【硬件部份】STC8H8K64U/STC8051U34K64 RA8889开发板 7寸TFT 800x480 1. 实物连接图:STC8H8K64URA8889开发板,使用P2口I2C接口: 2.实物连…

【python基础】类的继承、类导入、类的编写规范

文章目录 一. 继承1. 子类的方法__init__()2. 子类特有的属性和方法3. 重写父类的方法4. 类关系之引入:将实例用作属性 二. 导入类1. 导入类2. 在一个模块中导入另一个模块3. 使用别名导入并创建实例 三. Python标准库四. 类编码风格 一. 继承 一个类继承另一个类时…

log4j2启动异步日志与动态修改日志级别

启动异步日志 启用 Log4j2 的异步日志记录功能可以显著提升日志记录的性能,尤其是在高并发的环境下。异步日志记录通过将日志事件放入队列中进行处理,从而减少了日志记录对应用程序性能的影响。以下是如何启用 Log4j2 异步日志记录的详细步骤。 1. 添加…

【Python】写一篇setattr方法的使用博客

为何每次早餐 仍然魂离魄散 原来 那朝分手都要啜泣中上班 明明能够过得这关 赢回旁人盛赞 原来 顽强自爱这样难 难得的激情总枉费 残忍的好人都美丽 别怕 你将无人会代替 🎵 陈慧娴《情意结》 在 Python 中,动态地操作对象的属性是…

Oracle(15)什么是索引(Index)?

索引(Index)是数据库中一种用于提高查询性能的数据结构。索引在数据库表的一个或多个列上创建,类似于书的目录,通过索引可以快速定位和检索表中的数据行,而无需扫描整个表。尽管索引可以大幅提升查询性能,但…

2024 年 100 大数据科学面试问答

2024 年 100 大数据科学面试问答 一、说明 数据科学是一个快速发展的领域,它正在改变组织根据数据理解和做出决策的方式。因此,公司越来越多地寻求聘请数据科学家来帮助他们理解数据并推动业务成果。这导致了对数据科学家的高需求,这些职位的…

LeetCode 热题 HOT 100 (004/100)【宇宙最简单版】

【单调栈】No. 0739 每日温度 【中等】👉力扣对应题目指路 希望对你有帮助呀!!💜💜 如有更好理解的思路,欢迎大家留言补充 ~ 一起加油叭 💦 ⭐ 题目描述:给定一个整数数组 temperatu…