误解

如果,你问一个程序员,touch 命令是干什么的?

我相信 10 个里面有 8 个会回答:创建一个空文件。

然而,事实真的如此吗?

本意

man touch

man-touch

Linux man 手册里面介绍 到 touch - change file timestamps。所以,touch 的本意是改变文件的时间戳,即,将文件的访问时间和修改时间改为当前时间。

澄清

所以,创建一个空文件,只是 touch 的功能只一:当文件不存在时,使用当前时间创建一个空文件。

甚至,创建空文件你仍然可以理解为是改变文件的时间戳,改变为现在,也就从无到有创建了。另一种理解,一个文件不可能只有访问时间和修改时间而没有创建时间(那太邪乎了),而 touch 为了完成修改文件的访问时间和修改时间,不得已要给文件一个创建时间,就这样(误打误撞)把一个文件给创建了。

以上内容纯属瞎扯,哈哈!『Talk is cheap. Show me the code』 😋

源码

/* Update the time of file FILE according to the options given.
   Return 0 if successful, 1 if an error occurs. */
static int touch(const char *file)
{
...
    /* 文件不存在先创建 */
	if (!no_create) {
		/* Try to open FILE, creating it if necessary.  */
		fd = open(file, O_WRONLY | O_CREAT | O_NONBLOCK | O_NOCTTY,
				  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);

		/* Don't save a copy of errno if it's EISDIR, since that would lead
		 touch to give a bogus diagnostic for e.g., `touch /' (assuming
		 we don't own / or have write access to it).  On Solaris 5.6,
		 and probably other systems, it is EINVAL.  On SunOS4, it's EPERM.  */
		if (fd == -1 && errno != EISDIR && errno != EINVAL && errno != EPERM)
			open_errno = errno;
	}
...
    /* 更新文件的访问时间和修改时间 */
	if (amtime_now) {
		/* Pass NULL to utime so it will not fail if we just have
		 write access to the file, but don't own it.  */
		status = utime(file, NULL);
	} else {
		struct utimbuf utb;

		/* There's currently no interface to set file timestamps with
		 better than 1-second resolution, so discard any fractional
		 part of the source timestamp.  */

		if (use_ref) {
			utb.actime = ref_stats.st_atime;
			utb.modtime = ref_stats.st_mtime;
		} else
			utb.actime = utb.modtime = newtime;

		if (!(change_times & CH_ATIME))
			utb.actime = sbuf.st_atime;

		if (!(change_times & CH_MTIME))
			utb.modtime = sbuf.st_mtime;

		status = utime(file, &utb);
	}
...
	return 0;
}

从源码中可以清楚看到,touch 先检测文件是否存在,不存在就先创建,然后使用 utime() 系统调用,修改文件的访问时间和修改时间。