Imagine que eu queira mover (renomear) uma árvore de diretórios /var/lib/postgres/data
para /var/lib/postgres/data.old
:
/var/lib/postgres
└── data
├── base
│ ├── 16390
│ │ └── <...>
│ └── <...>
│ └── <...>
├── global
│ └── <...>
├── pg_wal
│ ├── <...>
│ ├── archive_status
│ └── summaries
├── <...>
└── postmaster.pid
Normalmente, basta uma única rename()
chamada de sistema e um único comando: mv data data.old
.
Entretanto, imagine que haja um ponto de montagem ativo em algum lugar nessa árvore de diretórios, por exemplo, pg_wal
em um sistema de arquivos diferente:
$ 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
<...>
Alternativamente, imagine que o nome de destino ( data.old
) já existe e alguns ramos da árvore de diretórios já foram criados (porque são pontos de montagem, na mesma linha acima).
~~Em ambos os casos~~ No último caso, mv
se recusará a fazer qualquer coisa. Executar uma cópia profunda com algo como a cp -a
é proibitivamente caro, e reflinks não estão disponíveis por razões que estão fora do escopo desta questão.
Existe uma ferramenta que pode executar um "movimento recursivo" ideal, descendo iterativamente em partes da hierarquia de origem para cada subárvore que não pode ser renomeada por completo, até arquivos individuais (finalmente voltando a fazer uma cópia de cada arquivo individual, se necessário)?
NB: Estou procurando uma solução generalizada que possa ser estendida a qualquer número de subárvores e conflitos, ou seja, mv data/* -t data.old; mv data/pg_wal/* -t data.old/pg_wal
não é uma solução. Em outras palavras, por favor, não infira nenhuma restrição ou caso especial do exemplo acima.
Use
cp -al
para vincular todos os arquivos ao diretório de destino:Repita para cada montagem filho. O comando relatará "Link entre dispositivos inválido" para o conteúdo do ponto de montagem, bem como
ln
faria.Por fim, exclua todo o diretório original.