Quebrando um link físico no local?


13

Estou mantendo meus dotfiles sob controle de versão e o script que os implementa cria links físicos. Eu também uso etckeeperpara colocar meu /etccontrole de versão sob. Recentemente, recebi avisos como este:

warning: hard-linked files could cause problems with bzr

Uma cópia simples ( cp filename.ext filename.ext) não funcionará:

cp: `filename.ext' and `filename.ext' are the same file

Renomear / mover um arquivo - exceto nos volumes - também não quebra o vínculo físico.

Então, minha pergunta é: existe uma maneira de quebrar um vínculo físico com um arquivo sem realmente precisar saber onde estão os outros vínculos físicos com esse arquivo?


2
O comando "rm" quebra os links físicos.
9278 Johan

Respostas:


14
cp -p filename filename.tmp
mv -f filename.tmp filename

Tornando programável:

dir=$(dirname -- "$filename")
tmp=$(TMPDIR=$dir mktemp)
cp -p -- "$filename" "$tmp"
mv -f -- "$tmp" "$filename"

Fazer a cópia primeiro e depois movê-la para o lugar tem a vantagem de que o arquivo muda atomicamente de um link físico para uma cópia separada (não há um ponto no tempo em que filenameesteja parcial ou ausente).


7

Você provavelmente quer dizer que deseja dividir o hard-link em um arquivo separado e independente.

mv hardlink tempname && cp tempname hardlink && rm tempname

Um hardlink é a conexão entre uma entrada no diretório e o bloco inode no disco.

inodes armazenam metadados de arquivos e, para arquivos pequenos, alguns sistemas de arquivos armazenam dados no inode, caso contrário, apontam para os blocos de dados e para arquivos muito grandes listas indiretas e indiretas e indiretas duplas de apontadores para unidades de alocação de disco.

Independentemente disso, a conexão entre o nome do arquivo (que é o que o comando ls produz) e o bloco inode que armazena esses metadados é chamada de link físico.

Ter vários links físicos para um único arquivo significa o mesmo inode referenciado por mais de uma entrada de diretório, possivelmente em diretórios diferentes (em um único sistema de arquivos)

rm exclui a entrada do nome do arquivo do diretório Depois que um inode não é mais referenciado por nenhum arquivo, seu espaço é liberado para uso por outros arquivos.


De fato. Isto é o que os exemplos cpe mvimplicaram. Portanto, não há como usar um arquivo temporário, pelo que vejo.
0xC0000022L

@ 0xC0000022L, Não, os inodes não contêm ponteiros para outros inodes. Apenas para blocos de dados (ou eles podem dobrar como espaço de dados se o objeto for pequeno).
precisa saber é o seguinte

4
Verifique se as permissões e outros dados são preservados ao copiar, ou seja. use cp -a(pelo menos GNU coreutils).
vonbrand

@ 0xC0000022L, se você observar com cuidado, existe apenas um nome temporário para o arquivo original, um novo arquivo será criado apenas na última etapa.
vonbrand

@ vonbrand Eles podem de fato, dependendo de qual sistema de arquivos está sendo usado.
Johan

4

Coloque isso no final do seu arquivo ~ / .bashrc.

delink () { tmpfile="$1$(date)"; cp -a "$1" "$tmpfile"; mv "$tmpfile" "$1"; }

Execute-o assim

delink filename

3

A melhor maneira de fazer isso com um script bash seria algo como isto:

if [ -f "$1" ] ; then
dir="$(dirname -- "$1")"
tmpfile="$(mktemp --tmpdir="$dir")"
cp --preserve=all -f -- "$1" "$tmpfile"
mv -f -- "$tmpfile" "$1"
fi

pontos a serem observados:

  • verifique se o arquivo é regular antes de tentar copiá-lo
  • mantenha o arquivo antigo no lugar até a cópia estar pronta
  • use mktemppara gerar um arquivo que é garantido que não existe
  • use -fpara forçar a substituição e --preserve=allmanter os metadados o mais semelhante possível ao arquivo original
  • use --e "para citar caminhos contendo espaços e / ou começando com-

Não é possível fazer a substituição sem criar um arquivo temporário com as chamadas atuais do sistema linux (3.16): embora seja possível sobrescrever um arquivo atomicamente (por exemplo, remover o arquivo antigo e substituí-lo por um novo como uma única operação), ele não é possível fazer isso com um arquivo que não tem nome no sistema de arquivos (ou seja, um arquivo temporário criado usando o O_TMPFILEsinalizador de openfunção) porque a renamefunção requer um nome de arquivo como entrada (não há uma versão renameque aceite como entrada um descritor de arquivo - veja aqui para detalhes)


1
Observe que você não conseguiu citar o nome nas chamadas dirnamee mktemp. Fixa que para você ...
derobert

@derobert oh obrigado, mas isso não vai funcionar, pois existem aspas duplas aninhadas ... precisa de outra correção! Tipo de ódio bash
pqnet

3
Funcionará por causa da $( ... )substituição do comando -style. Um dos motivos é o melhor ` ... `estilo.
Derobert

@derobert bom, não sabia disso. Além disso, como você pode usar `dentro de tags de código embutido?
pqnet

Você pode escapar deles com barras invertidas. Então, para `você colocar: `\``(é claro, eu escapei duas vezes para mostrar o que você digita).
Derobert

-1

O comando que você está procurando é unlink


Talvez minha pergunta não tenha sido clara, mas por "in-loco" e pelos exemplos com cpe mveu pretendi deixar claro que desejo que o arquivo exista depois.
0xC0000022L

Ah, eu não achei isso claro, não. Você deveria ir com a resposta de Johan, então.
Jenny D

1
O comando "desvincular" simplesmente remove o arquivo (o que a chamada do sistema unlink () faz).
Raúl Salinas-Monteagudo

-1

Se você estiver procurando por todos os nomes de arquivos com links diretos para esse arquivo, poderá usar:

find -samefile myknowhardlinkfile

também ls -il myknowhardlinkfilemostrará o número do nome do arquivo vinculado ao mesmo inode (terceiro campo).

101612442 -rw-rw-r--. 2 me me 0 Aug  5 07:07 myknowhardlinkfile

Na verdade, isso não responde à pergunta, embora possa ser útil.
Flimm 27/09/16
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.