Eu tenho uma pasta que contém um certo número de arquivos que possuem links físicos (na mesma pasta ou em outro lugar) e quero desassociá-los, para que eles se tornem independentes e as alterações no conteúdo não afetem outro arquivo (a contagem de links se torna 1).
Abaixo, dou uma solução que basicamente copia cada link físico para outro local e depois o move novamente.
No entanto, esse método parece bastante grosseiro e propenso a erros, então eu gostaria de saber se existe algum comando que elimine o link de um arquivo para mim.
Resposta bruta:
Encontre arquivos com links físicos ( Editar : para também encontrar soquetes etc. que tenham links físicos, use find -not -type d -links +1
):
find -type f -links +1 # files only
find -not -type d -links +1 # files, sockets etc.
Um método simples para desassociar um arquivo (copie-o para outro local e mova-o de volta):
Editar: Como o Celada disse, é melhor fazer um cp -p abaixo, para evitar a perda de carimbos de data e hora e permissões. Editar: Crie um diretório temporário e copie para um arquivo abaixo dele, em vez de sobrescrever um arquivo temporário, minimiza o risco de sobrescrever alguns dados, embora o mv
comando ainda seja arriscado (obrigado @Tobu). Editar: tente criar o diretório temporário no mesmo sistema de arquivos (@MikkoRantalainen).
# This is unhardlink.sh
set -e
for i in "$@"; do
temp="$(mktemp -d -- "${i%/*}/hardlnk-XXXXXXXX")"
[ -e "$temp" ] && cp -ip "$i" "$temp/tempcopy" && mv "$temp/tempcopy" "$i" && rmdir "$temp"
done
Portanto, para desassociar todos os links físicos ( Editar : alterado -type f
para -not -type d
, veja acima):
find -not -type d -links +1 -print0 | xargs -0 unhardlink.sh
cp -i
opção, ele cuspiu algumas mensagens perguntando se deveria substituir./fileXXXXXX
(o$temp
arquivo), mesmo que tmpfile deva dar nomes de arquivo exclusivos, portanto, é necessário seja algum tipo de condição de corrida ou o que seja, e com isso o risco de perder alguns dados.unhardlink.sh
deve criar um diretório temporário dentro do mesmo diretório que contém o arquivo que precisa ser desvinculado. Caso contrário, sua chamada recursiva poderá se repetir dentro de outro sistema de arquivos e você acabará movendo as coisas além dos limites do sistema de arquivos porque seu diretório temporário está no diretório de trabalho atual. Eu acho que você poderia passar"$(dirname "$i")/hardlink-XXXXXX"
como argumento para mktemp.fuse
sistema de arquivos, ele poderá realmente ser enviadopath/to/hardlink-XXX
para uma mídia de armazenamento físico diferentepath/to/original-file
, mas não há muito o que fazer sobre isso.Respostas:
Há espaço para melhorias em seu script, por exemplo, adicionando uma
-p
opção aocp
comando para que as permissões e os carimbos de data e hora sejam preservados em toda a operação de desarticulação, e você pode adicionar algum tratamento de erros para que o arquivo temporário seja excluído em caso de erro, mas a idéia básica da sua solução é a única que funcionará. Para desvincular um arquivo, você deve copiá-lo e, em seguida, mover a cópia novamente sobre o nome original. Não há solução "menos grosseira", e essa solução tem condições de corrida, caso outro processo esteja acessando o arquivo ao mesmo tempo.fonte
Se você deseja economizar espaço em disco e possui uma versão relativamente moderna
tar
(por exemplo, o que está no Ubuntu 10.04 e CentOS 6), pode jogar com a--hard-dereference
opçãoAlgo como:
(onde eu corri
ln foo/[12] bar
)Na página do manual:
fonte
cp -a --no-preserve=links /path/to/folder /path/to/copy && rm -rf /path/to/folder && mv /path/to/copy /path/to/folder
, se não me engano. Eu acho que seu método seria mais eficiente, no entanto, porque o tar envolveria menos buscas de disco e, portanto, menos problemas. Pode-se conseguir o mesmo com o rsync, com desempenho ainda menor que o método cp :).tar cvf - --hard-dereference . | tar xf -
mas pode haver uma condição de corrida que fará com que as coisas explodam. Eu não tentei e estou meio que desanimado em fazê-lo no momento.