A página cp
do comando info
oferece na opção --preserve=
o seguinte:
links
Preserve nos arquivos de destino quaisquer links entre os arquivos de origem correspondentes. Observe quecom-L' or
-H', esta opçãopodeconverter links simbólicos em links físicos.
seguido por um exemplo que não entendo [agora]; de qualquer forma:
Pergunta: Como transformar soft- em hardlinks com cp
? E há um caminho de volta também [convertendo hard-links em softlinks]?
Problema Secundário: Ondepodena citação acima entra em jogo? Eu entendo o propósito de -L
e -H
, sou capaz de copiar softlinks totalmente funcionais, etc., mas até agora não consegui transformar soft-links em hardlinks.
Responder1
O exemplo na página de informações mostra como o exemplo é um pouco difícil de seguir:
$ mkdir c; : > a; ln -s a b; cp -aH a b c; ls -i1 c
74161745 a
74161745 b
Vamos dividir isso em seus comandos componentes:
mkdir c;
: cria o diretórioc/
: > a;
: apenas uma maneira rápida de criar um arquivo vazio. É equivalente aecho "" > a
.:
é um bash embutido que não faz nada, vejahelp :
.ln -s a b
: crie um softlink paraa
chamadob
. Neste ponto, este é o conteúdo do diretório atual:$ ls -l | cc2ter total 4 -rw-r--r-- 1 terdon terdon 0 Oct 9 02:50 a lrwxrwxrwx 1 terdon terdon 1 Oct 9 02:50 b -> a drwxr-xr-x 2 terdon terdon 4096 Oct 9 02:50 c
Observe que
b
é um link simbólico (soft link) e não aponta para o mesmo inode quea
:$ ls -i1c a b 16647344 a 16647362 b
cp -aH a b c;
: copie os arquivosa
parab
o diretórioc
. É aqui que a conversão está acontecendo, as opções passadascp
são:-a, --archive same as -dR --preserve=all -d same as --no-dereference --preserve=links -H follow command-line symbolic links in SOURCE
O
-H
é necessário porque (deinfo cp
):Ao copiar de um link simbólico, `cp' normalmente segue o link apenas quando não está copiando recursivamente.
Como
-a
ativa a cópia recursiva (-R
),-H
é necessário seguir links simbólicos.-H
significa que os links são seguidos apesar da recursão e resultarão na criação de links físicos no diretório de destino. Este é o conteúdoc/
após a última etapa (a primeira coluna é o número do inode):$ ls -li c total 0 17044704 -rw-r--r-- 2 terdon terdon 0 Oct 9 02:50 a 17044704 -rw-r--r-- 2 terdon terdon 0 Oct 9 02:50 b
Agora, como exatamente funciona, pelo que pude descobrir brincando com ele, cp --preserve=links
combinado -L
ou -H
converterá links simbólicos em links físicos setanto o link quanto o destino estão sendo copiados para omesmodiretório.
Na verdade, como o OPdescobriu, pelo menos em sistemas Debian, cp --preserve=links
é suficiente para converter links simbólicos em links físicos se o diretório de destino for o mesmo.
Responder2
Enviei um relatório sobre um possível bug para a equipe coreutils @gnu.org na info cp
documentação e recebi esta resposta:
Os documentos são um pouco concisos aqui. A questão principal é que -a implica -d e isso implica --no-dereference que é necessário para que seus comandos funcionem conforme o esperado. IE --no-dereference é necessário para parar cp implicitamente seguindo links simbólicos na fonte.
Para verificar e dividir os detalhes demonstrados aqui:
$ mkdir links; : > a; ln -s a b;
Aqui vemos que -d substitui -H conforme vem depois. Portanto, não iremos desreferenciar links simbólicos em primeiro lugar.
$ rm links/*; cp -H -d a b links $ l links/ lrwxrwxrwx. 1 padraig 1 Oct 10 09:37 b ▪▶ a -rw-rw-r--. 1 padraig 0 Oct 10 09:37 a
Aqui vemos que -H agora é respeitado por último e, portanto, os links simbólicos são seguidos na origem, resultando em hardlinks no destino.
$ rm links/* $ rm links/*; cp -d -H a b links $ l links -rw-rw-r--. 2 padraig 0 Oct 10 09:37 b -rw-rw-r--. 2 padraig 0 Oct 10 09:37 a
Vou tornar os documentos um pouco mais explícitos com o seguinte:
diff --git a/doc/coreutils.texi b/doc/coreutils.texi index b273627..aeed4ca 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -8257,9 +8257,11 @@ $ mkdir c; : > a; ln -s a b; cp -aH a b c; ls -i1 c @noindent
Observe as entradas:
@file{b}
é um link simbólico para file normal@file{a}
, mas os arquivos no diretório de destino,@file{c/}
, são vinculados fisicamente.
- Desde que
@option{-a}
implica@option{--preserve=links}
, e desde que@option{-H}
diz@command{cp}
para desreferenciar os argumentos da linha de comando, ele vê dois arquivos com o mesmo número de inode e preserva o link físico percebido.- Uma vez que
@option{-a}
implica@option{--no-dereference}
que copiaria o link simbólico, mas o posterior@option{-H}
informa@command{cp}
para desreferenciar os argumentos da linha de comando, onde verá dois arquivos com o mesmo número de inode. Então a@option{--preserve=links}
opção também implícita em@option{-a}
preservará o link físico percebido.
Responder3
Seria difícil converter links físicos em links simbólicos. No caso de um link físico, existe um bloco de dados no sistema de arquivos que possui duas ou mais entradas de arquivo apontando para ele. Não existe “fonte” e “destino”; é literalmente um arquivo com vários nomes equivalentes. Você pode usar o GNU find para identificá-los desta forma:
sauer@zipper:~$ find . -type f -links +1 -printf "%i: %p (%n)\n"
609: ./link1 (2)
609: ./link2 (2)
Depois de obter todos os arquivos com o mesmo inode, você terá que escolher um para ser o arquivo "real" e então substituir todos os outros por links simbólicos para o arquivo mestre. Provavelmente a maneira de fazer isso seria usar isto:
sauer@zipper:~$ find . -type f -links +1 -printf "%i %p\n" | sort -nk1
609 ./link1
609 ./link2
E então faça com que um script descubra como escolher um dos valores com o mesmo número para que todos os outros sejam vinculados a ele. Talvez o primeiro se torne o alvo, e qualquer outro com o mesmo inode esteja vinculado a ele. Aqui está um exemplo de script de shell realmente simples e não testado
#!/bin/sh
prev=""
target=""
find /tmp -type f -links +1 -printf "%i %p\n" | sort -nk1 \
| while read inode file
do
if [[ $inode != $prev ]]
then
target="$file"
prev=$inode
else
ln -sf "$target" "$file"
fi
done
Existem problemas potenciais, pois links de diretórios diferentes podem ser criados com um destino inválido se o caminho em find (/tmp neste exemplo) não for absoluto. Mas a ideia geral deve funcionar bem.