Rompere un hard link sul posto?


13

Sto mantenendo i miei dotfile sotto il controllo della versione e lo script che li distribuisce crea collegamenti reali. Io uso anche etckeeperdi mettere il mio /etccontrollo di versione sotto. Recentemente ho ricevuto avvisi come questo:

warning: hard-linked files could cause problems with bzr

Una semplice copia ( cp filename.ext filename.ext) non funzionerà:

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

Rinominare / spostare un file - eccetto su più volumi - inoltre non interrompe il collegamento reale.

Quindi la mia domanda è: c'è un modo per interrompere un collegamento reale a un file senza realmente sapere dove sono / sono gli altri collegamenti reali a quel file?


2
Il comando "rm" interrompe i collegamenti reali.
Johan

Risposte:


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

Rendendolo programmabile:

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

Eseguendo prima la copia, quindi spostandola in posizione, si ha il vantaggio che il file cambia atomicamente dall'essere un collegamento reale all'essere una copia separata (non esiste un punto nel tempo in cui filenameè parziale o mancante).


7

Probabilmente vuoi dire che vuoi dividere l'hard link in un file separato e indipendente.

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

Un collegamento fisico è la connessione tra una voce nella directory e il blocco di inode sul disco.

gli inode memorizzano i metadati dei file e, per piccoli file, alcuni file system memorizzano i dati nell'inode, altrimenti puntatori ai blocchi di dati e per file molto grandi elenchi indiretti e doppio-indiretti di puntatori alle unità di allocazione del disco.

Indipendentemente da ciò, la connessione tra il nome del file (che è ciò che produce il comando ls) e il blocco inode che memorizza questi metadati, è chiamato hard link.

Avere più collegamenti fissi a un singolo file significa lo stesso inode a cui fa riferimento più di una voce di directory, possibilmente in directory diverse (su un singolo file system)

rm cancella la voce del nome file dalla directory. Quando un inode non fa più riferimento a nessun file, il suo spazio viene liberato per essere utilizzato da altri file.


Infatti. Questo è ciò cpche mvimplicavano gli esempi. Quindi non posso assolutamente usare un file temporaneo, vedo.
0xC0000022L

@ 0xC0000022L, No, gli inode non contengono puntatori ad altri inode. Solo per blocchi di dati (o possono raddoppiare come spazio dati se l'oggetto è piccolo).
vonbrand

4
Assicurarsi che le autorizzazioni e altri dati siano conservati durante la copia, ad es. uso cp -a(almeno coreutils GNU).
vonbrand

@ 0xC0000022L, se osservi attentamente, esiste solo un nome temporaneo per il file originale, un nuovo file viene creato solo nell'ultimo passaggio.
vonbrand

@vonbrand Possono davvero, a seconda del file system utilizzato.
Johan

4

Mettilo alla fine del tuo file ~ / .bashrc.

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

Eseguilo in questo modo

delink filename

3

Il modo migliore per farlo con uno script bash sarebbe qualcosa del genere:

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

punti da notare:

  • controlla se il file è un file normale prima di provare a copiarlo
  • mantenere il vecchio file in posizione fino a quando la copia è pronta
  • utilizzare mktempper generare un file che è garantito che non esiste
  • utilizzare -fper forzare la sovrascrittura e --preserve=allmantenere i metadati il ​​più simili possibile al file originale
  • usare --e "per citare percorsi contenenti spazi e / o che iniziano con-

Effettuare la sostituzione senza creare un file temporaneo non è possibile con le chiamate di sistema linux (3.16) correnti: mentre è possibile sovrascrivere atomicamente un file (cioè rimuovere il vecchio file e sostituirlo con uno nuovo come una singola operazione), esso non è possibile farlo con un file che non ha un nome sul filesystem (cioè un file temporaneo creato usando il O_TMPFILEflag di openfunzione) perché la renamefunzione richiede un nome file come input (non esiste una versione renameche assume come input un descrittore di file - vedi qui per i dettagli)


1
Nota che non sei riuscito a citare il nome nel tuo dirnamee mktempchiama. Risolto il
problema

@derobert oh grazie, ma questo non funzionerà poiché ci sono doppie virgolette nidificate ... serve un'altra correzione! Kinda hate bash
pqnet,

3
Funzionerà a causa della $( ... )sostituzione del comando -style. Uno dei motivi è più bello dello ` ... `stile.
derobert,

@derobert simpatico, non lo sapevo. Inoltre, come puoi usare `dentro i tag di codice inline?
pqnet,

Puoi sfuggirli con le barre rovesciate. Quindi per farti `mettere: `\``(ovviamente, sono scappato due volte per farti vedere quello che scrivi).
derobert,

-1

Il comando che stai cercando è unlink


Forse la mia domanda non era chiara, ma per "sul posto" e gli esempi con cpe mvintendevo chiarire che avrei voluto che il file esistesse in seguito.
0xC0000022L

Ah, non l'ho trovato chiaro, no. Dovresti seguire la risposta di Johan, quindi.
Jenny D

1
Il comando "unlink" rimuove semplicemente il file (cosa fa la chiamata di sistema unlink ()).
Raúl Salinas-Monteagudo,

-1

Se stai cercando tutti i nomi di file che sono hardlink a questo file, puoi usare:

find -samefile myknowhardlinkfile

ls -il myknowhardlinkfilemostrerà anche il numero di nome file collegato allo stesso inode (terzo campo).

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

Questo in realtà non risponde alla domanda, sebbene possa essere utile.
Flimm,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.