假设我想将目录树移动(重命名)/var/lib/postgres/data
到/var/lib/postgres/data.old
:
/var/lib/postgres
└── data
├── base
│ ├── 16390
│ │ └── <...>
│ └── <...>
│ └── <...>
├── global
│ └── <...>
├── pg_wal
│ ├── <...>
│ ├── archive_status
│ └── summaries
├── <...>
└── postmaster.pid
通常,它只需一个rename()
系统调用和一个命令即可:mv data data.old
。
但是,想象一下该目录树中的某个地方有一个活动的挂载点,例如,pg_wal
是一个不同的文件系统:
$ findmnt
<...>
├─/var/lib/postgres stank/data/stratofortress/PostgreSQL zfs rw,noatime,xattr,posixacl,casesensitive
│ └─/var/lib/postgres/data/pg_wal stank/data/stratofortress/PostgreSQL/pg_wal zfs rw,noatime,xattr,posixacl,case-sensitive
<...>
或者,假设目标名称(data.old
)已经存在,并且目录树的某些分支已经创建(因为它们是挂载点,与上面的情况相同)。
~~在这两种情况下~~在后一种情况下,mv
将拒绝执行任何操作。使用类似的东西执行深度复制的成本cp -a
非常高,并且由于超出了本问题范围的原因,reflinks 不可用。
是否有一个工具可以执行最佳的“递归移动”,迭代地下降到源层次结构中无法批量重命名的每个子树的部分,直至单个文件(最终回到制作每个单独文件的副本,如果需要)?
注意:我正在寻找一种可以扩展到任意数量的子树和冲突的通用解决方案,即mv data/* -t data.old; mv data/pg_wal/* -t data.old/pg_wal
不是解决方案。换句话说,请不要从上面的示例中推断出任何约束或特殊情况。
用于
cp -al
将所有文件硬链接到目标目录:对每个子挂载重复此操作。该命令将报告挂载点内容的“跨设备链接无效”,就像
ln
会一样。最后,删除整个原始目录。