使用 mv 将文件夹替换为另一个文件夹(无需先删除目标文件夹)

fab*_*gli 5 bash shell command-line mv

我正在尝试用 adirectory来替换现有的folder,但无法用 mv 完成它 - 我相信有一种方法,但我只是不知道(还)。即使在查阅了手册页并搜索了网络之后也是如此。

如果/path/to/仅包含directory,则以下命令将移动/path/to/directory(消失)到/path/to/folder

mv /path/to/directory /path/to/folder
Run Code Online (Sandbox Code Playgroud)

它基本上是一个重命名,这就是我试图实现的目标。

但如果/path/to/folder已经存在,相同的命令会将 移动/path/to/directory/path/to/folder/directory

我不想使用cp命令来避免IO。

che*_*ner 4

使用 来“复制”指向文件的指针,而不是cp实际复制每个文件中的数据ln

ln /path/to/directory/* /path/to/folder && rm -rf /path/to/directory
Run Code Online (Sandbox Code Playgroud)

请注意,这比使用;稍微cp更原子一些。每个单独的文件都在/path/to/folder一个步骤中出现(即,不可能被/path/to/folder/foo.txt部分复制),但仍然有一个小窗口,其中一些(但不是全部)文件已/path/to/directory链接到folder. 另外,rm -rf不是原子的,但假设没有人对 感兴趣directory,这不是问题。(尽管如此,由于来自的文件/path/to/directory未链接,您可以看到文件的链接计数/path/to/foldoer从 2 更改为 1。不太可能有人会关心这一点。)


您所认为的文件实际上只是文件系统管理的匿名文件的文件系统条目。例如,考虑一个简单的例子。

$ mkdir d
$ cd d
$ echo hello > file.txt
$ cp file.txt file_copy.txt
$ ln file.txt file_link.txt
$ ls -li
total 24
12890456377 -rw-r--r--  2 chepner  staff  6 Mar  3 12:46 file.txt
12890456378 -rw-r--r--  1 chepner  staff  6 Mar  3 12:47 file_copy.txt
12890456377 -rw-r--r--  2 chepner  staff  6 Mar  3 12:46 file_link.txt
Run Code Online (Sandbox Code Playgroud)

-i选项将每个条目的索引节点号(第一列)添加到输出中;索引节点可以被认为是文件的唯一标识符。在此输出中,您可以看到这file_copy.txt是一个全新的文件,其索引节点与file.txt. file_link.txt具有完全相同的索引节点,这意味着file.txtfile_link.txt只是同一事物的两个不同名称。所有者之前的数字是链接计数file.txt两者file_link.txt都引用链接计数为 2 的文件。

当您使用 时rm,您只是删除文件的链接,而不是文件本身。在链接计数减少到 0 之前,不会删除文件。为了演示,我们将删除file.txtfile_copy.txt

$ rm file.txt file_copy.txt
$ ls -li
total 8
12890456377 -rw-r--r--  1 chepner  staff  6 Mar  3 12:46 file_link.txt
Run Code Online (Sandbox Code Playgroud)

如您所见,唯一的链接file_copy已消失,因此 inode 12890456378 不再出现在输出中。(数据是否真的消失是文件系统实现的问题。)file_link.txt尽管如此,仍然引用与以前相同的文件,但现在链接计数为 1,因为file.txt已被删除。

文件的链接不必出现在同一目录中;它们可以出现在同一文件系统上的任何目录中,这是使用此技巧的唯一警告。ln如果您尝试创建指向另一个文件系统上的文件的链接,IIRC 将会给您一个错误。