Como copiar um diretório recursivamente usando hardlinks para cada arquivo

46

Eu quero criar uma "cópia" de uma árvore de diretórios onde cada arquivo é um hardlink para o arquivo original

Exemplo: eu tenho uma estrutura de diretórios:

dirA/
dirA/file1
dirA/x/
dirA/x/file2
dirA/y/
dirA/y/file3

Aqui está o resultado esperado, uma "cópia" da árvore de diretórios em que cada arquivo é um link físico para o arquivo original:

dirB/            #  normal directory
dirB/file1       #  hardlink to dirA/file1
dirB/x/          #  normal directory
dirB/x/file2     #  hardlink to dirA/x/file2
dirB/y/          #  normal directory
dirB/y/file3     #  hardlink to dirA/y/file3
    
por Gudmundur Orn 09.05.2015 / 17:25

4 respostas

44

No Linux (mais precisamente com as implementações GNU e busybox de cp como normalmente encontradas em sistemas que possuem o Linux como kernel) e o FreeBSD recente, é assim:

cp -al dirA dirB

Para uma solução mais portátil, veja a resposta usando pax e cpio por Stéphane Chazelas

    
por 09.05.2015 / 17:26
23

POSIXly, você usaria pax no modo de leitura + gravação com a opção -l :

pax -rwlpe -s /A/B/ dirA .

( -pe preserva todos os atributos possíveis de arquivos (neste caso apenas diretórios) que são copiados, como o cp do GNU -a ).

Agora, embora padrão , esse comando não é necessariamente muito portátil .

Primeiro, muitos sistemas baseados em GNU / Linux não incluem pax por padrão (mesmo que seja um utilitário POSIX não-opcional).

Em seguida, vários bugs e não-conformidades com algumas implementações causam vários problemas com esse código.

  • devido a um erro, o Solaris 10 pax (pelo menos) não funciona ao usar -rwl em combinação com -s . Por alguma razão, parece que aplica a substituição ao caminho original e copiado. Então, acima, ele tentaria fazer alguns link("dirB/file", "dirB/file") em vez de link("dirA/file", "dirB/file") .
  • no FreeBSD, pax não cria hardlinks para arquivos do tipo symlink (um comportamento permitido pelo POSIX). Não só isso, mas também aplica a substituição aos alvos dos links simbólicos (um comportamento não permitido pelo POSIX). Por exemplo, se houver um link simbólico foo -> AA em dirA , ele se tornará foo -> BA em dirB .

Além disso, se você quiser fazer o mesmo, mas com caminhos de arquivo arbitrários cujo conteúdo é armazenado em $src e $dst , é importante perceber que pax -rwl -- "$src" "$dst" cria a estrutura de diretório completa de $src inside $dst (que tem que existir e ser um diretório). Por exemplo, se $src for foo/bar , então, $dst/foo/bar será criado.

Se, em vez disso, você quiser que $dst seja uma cópia de $src , é mais fácil fazer isso como:

absolute_dst=$(umask 077 && mkdir -p -- "$dst" && cd -P -- "$dst" && pwd -P) &&
(cd -P -- "$src" && pax -rwlpe . "$absolute_dst")

(que também funcionaria em torno da maioria dos problemas mencionados acima, mas falharia se o caminho absoluto de $dst terminasse em caracteres de nova linha).

Agora, isso não ajudará nos sistemas GNU / Linux, onde não há pax .

É interessante notar que pax foi criado pelo POSIX para mesclar os recursos dos comandos tar e cpio .

cpio é um comando histórico Unix (de 1977) em oposição a uma invenção POSIX, e há também uma implementação GNU (não é pax one). Portanto, mesmo que não seja mais um comando padrão (era no SUSv2), ainda é muito comum e há um conjunto principal de recursos em que você pode confiar normalmente.

O equivalente a pax -rwl seria cpio -pl . No entanto:

  1. cpio pega a lista do arquivo de entrada em stdin, ao contrário dos argumentos (delimitada por nova linha, o que significa que os nomes de arquivo com caracteres de nova linha não são suportados)
  2. Todos os arquivos precisam ser especificados (normalmente, você fornece a saída de find ( find e cpio foram desenvolvidos em conjunto pelas mesmas pessoas)).
  3. Os metadados
  4. não são preservados (algumas cpio implementações têm opções para preservar algumas, mas nada portáveis).

Então, com cpio :

absolute_dst=$(umask 077 && mkdir -p -- "$dst" && cd -P -- "$dst" && pwd -P) &&
(cd -P -- "$src" && find . | cpio -pl "$absolute_dst")
    
por 09.05.2015 / 17:51
5

Resposta curta:

cd $source_folder
pax -rwlpe . $dest_folder
    
por 06.09.2016 / 22:31
2

Caso você esteja procurando por esse recurso copiar-com-hardlinks para fazer instantâneos ou backups de (todos ou parte de) seus arquivos, consulte rsnapshot .

    
por 09.05.2015 / 17:33