Determinare se un file è un collegamento reale o simbolico?


52

Sto creando uno script shell che prenderebbe un nome file / percorso a un file e determinerà se il file è un collegamento simbolico o un collegamento reale.

L'unica cosa è che non so come vedere se sono un collegamento reale. Ho creato 2 file, uno un collegamento reale e uno un collegamento simbolico, da utilizzare come file di prova. Ma come posso determinare se un file è un collegamento reale o simbolico all'interno di uno script di shell?

Inoltre, come troverei la partizione di destinazione di un collegamento simbolico? Quindi diciamo che ho un file che si collega a una diversa partizione, come troverei il percorso di quel file originale?


16
Cosa intendi con hard link? Tutti i file sono collegamenti reali.
terdon

1
@terdon ln /foo/bar/ /foo/bar2crea un hardlink mentre ln -s /foo/bar /foo/bar2crea un symlink, questo è ciò che intende?
DisplayName

14
@DisplayName sì, ma tutti i file sono hard link al loro inode. Ecco come funzionano i file system Linux. Nel tuo esempio, bar2e barsono entrambi collegamenti reali, puntando semplicemente allo stesso inode.
terdon

10
@DisplayName sì, sono collegamenti diretti ad altri inode . Non c'è contraddizione qui. Un file è un collegamento a un inode. Questa è la definizione di un file. Nel tuo caso, hai questi collegamenti in luoghi diversi ma ciò non cambia la struttura dei dati sottostante. Il mio punto è che entrambi bare bar2sono ugualmente importanti. Uno non è un collegamento all'altro, sono entrambi collegamenti ma puntano allo stesso inode.
terdon

3
@Scott no, sto dicendo che i file normali sono hardlink e che i hardlink creati da lnnon sono diversi dai file normali.
terdon

Risposte:


42

La risposta di Jim spiega come testare un collegamento simbolico: usando testil -Ltest di.

Ma testare un "hard link" non è, a rigor di termini, quello che vuoi. I collegamenti fisici funzionano grazie al modo in cui Unix gestisce i file: ogni file è rappresentato da un singolo inode. Quindi un singolo inode ha zero o più nomi o voci di directory o, tecnicamente, hard link (quello che stai chiamando un "file").

Per fortuna, il statcomando, ove disponibile, può dirti quanti nomi ha un inode.

Quindi stai cercando qualcosa del genere (qui assumendo l'implementazione GNU o busybox di stat):

if [ "$(stat -c %h -- "$file")" -gt 1 ]; then
    echo "File has more than one name."
fi

Il -c '%h'bit dice statdi emettere semplicemente il numero di hardlink sull'inode, cioè il numero di nomi che il file ha. -gt 1quindi controlla se è maggiore di 1.

Si noti che i collegamenti simbolici, proprio come qualsiasi altro file, possono anche essere collegati a più directory in modo da poter disporre di più collegamenti fisici a un collegamento simbolico.


ok, per essere chiari, posso generare il numero di hardlink che il file ha usando il comando stat e se è maggiore di 1, allora ha un altro file collegato da qualche parte sulla partizione.
k-Rocker,

@ k-Rocker Sì. Quindi ha un secondo nome da qualche parte sulla partizione.
derobert,

1
Su OS X o * BSD, lo è stat -f %l /path/to/file. Puoi anche usarlo gstat -c %h /path/to/filese hai i coreutils GNU installati senza i loro nomi predefiniti (con Homebrew su OS X).
PIL2,

29

Un esempio:

$ touch f1
$ ln f1 f2
$ ln f1 f3
$ ln -s f1 s1
$ ln -s f2 s2
$ ln -s ./././f3 s3
$ ln -s s3 s4
$ ln s4 s5
$ ls -li
total 0
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f3
10802345 lrwxrwxrwx 1 stephane stephane 2 Nov 12 19:56 s1 -> f1
10802346 lrwxrwxrwx 1 stephane stephane 2 Nov 12 19:56 s2 -> f2
10802347 lrwxrwxrwx 1 stephane stephane 8 Nov 12 19:56 s3 -> ./././f3
10802384 lrwxrwxrwx 2 stephane stephane 2 Nov 12 19:56 s4 -> s3
10802384 lrwxrwxrwx 2 stephane stephane 2 Nov 12 19:56 s5 -> s3

I f1, f2e le f3voci della rubrica sono lo stesso file (stessa inode: 10.802.124, si noterà il numero di collegamenti è 3). Sono collegamenti reali allo stesso file normale .

s4e s5sono anche lo stesso file (10802384). Sono di tipo symlink , non regolari . Indicano un percorso, qui s3. Perché s4e s5sono voci della stessa directory, quel percorso relativo s3punta allo stesso file (quello con inod 10802347) per entrambi.

Se lo fai ls -Ll, ti viene chiesto di ottenere informazioni sui file dopo aver risolto i collegamenti simbolici:

$ ls -lLi
total 0
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f3
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s3
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s4
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s5

Scoprirai che tutti si risolvono nello stesso file (10802124).

Puoi verificare se un file è un collegamento simbolico a [ -L file ]. Allo stesso modo, è possibile verificare se un file è un file normale [ -f file ], ma in tal caso, il controllo viene eseguito dopo aver risolto i collegamenti simbolici.

gli hardlink non sono un tipo di file, sono solo nomi diversi per un file (di qualsiasi tipo).


19

Utilizzando gli operatori -he -Ldel testcomando:

-h file 
true if file is a symbolic link

-L file 
true if file is a symbolic link

http://www.mkssoftware.com/docs/man1/test.1.asp

Secondo questo thread SO , hanno lo stesso comportamento, ma -Lè preferito.


ok fico, ma per quanto riguarda gli hard link? ho controllato il battistrada, ma niente di hard link. Se -L restituisce false, significa che è un collegamento reale? o solo un file normale?
k-Rocker,

1
Gli hard link condividono lo stesso inode. Inoltre, i soft link mostrano lall'inizio del suo ls -loutput ... Penso che potresti essere in grado di mettere insieme quelle regole in uno script, oltre al [[ -L file ]]test per vedere se il file dato è soft o hard .
jimm-cl,

ok, inoltre, come troverei la partizione di destinazione del collegamento simbolico?
k-Rocker,

3

Ci sono molte risposte abbastanza corrette qui, ma non credo che nessuno abbia davvero affrontato la percezione sbagliata originale. La domanda originale è sostanzialmente "quando creo un collegamento simbolico, è facile identificarlo in seguito. Ma non riesco a capire come identificare un collegamento reale". E sì, le risposte sostanzialmente si riducono a "non puoi", e più o meno spiegano perché, ma nessuno sembra aver riconosciuto che, in realtà, è confuso e strano.

Se stai leggendo tutto questo e hai capito cosa sta succedendo, allora sei bravo; non hai bisogno di leggere il mio pezzettino. Se sei ancora confuso, allora continua.

La risposta davvero molto breve è che un collegamento reale non è affatto un collegamento, non come un collegamento simbolico. È una nuova voce nella struttura della directory che punta allo stesso gruppo di byte della voce della directory originale e, una volta creata, è "reale" e legittima come la prima. Ogni file 'normale' sul tuo disco ha almeno un collegamento reale; senza quello, non lo vedresti in nessunodirectory e non sarebbe in grado di fare riferimento a esso o utilizzarlo. Quindi, se si dispone di un file Fred.txt e si collega ad esso Wilma.txt e Barney.txt, tutti e tre i nomi (e le voci della directory) si riferiscono allo stesso file e sono tutti ugualmente validi. Non c'è modo per il sistema operativo di dire che una delle voci è stata creata quando si preme "salva" nell'editor di testo e le altre sono state create con il comando "ln".

Il sistema operativo non deve tenere traccia di come molte voci differenti puntano allo stesso file, però. Se elimini Wilma.txt, non sorprende che non liberi spazio sul tuo disco. Ma se elimini Fred.txt (il file 'originale'), non libererai ancora spazio sul tuo disco, perché i dati sul disco che erano conosciuti come Fred.txt sono ancora Barney.txt. Solo quando si eliminano tutte le voci della directory, il sistema operativo disalloca lo spazio occupato dai dati stessi.

Se Barney.txt fosse stato un collegamento simbolico, l'eliminazione di Fred.txt avrebbe disallocato lo spazio e Barney.txt ora sarebbe un collegamento interrotto. Inoltre, se sposti o rinomini un file che ha un collegamento simbolico puntato verso di esso, interrompi il collegamento. Ma puoi spostare o rinominare un file hard-link tutto quello che vuoi senza rompere le altre voci di directory che puntano a quel file / dato, perché tutte sono voci di directory che si riferiscono allo stesso blocco di dati sull'unità (usando il inode # di tali dati).

[Sono passati due anni e quell'ultima parte mi ha confuso per un minuto, quindi penso che chiarirò. Se digiti "mv ./Wilma.txt ../elsewhere/Betty.txt" sembra che tu stia spostando il file, ma in realtà non lo sei. Quello che stai realmente facendo è rimuovere un elemento pubblicitario dall'elenco di directory della tua directory corrente, quello che dice "il nome 'Wilma.txt' è associato ai dati che puoi trovare usando l'inode ###### #, "e aggiungendo un nuovo elemento pubblicitario all'elenco di directory della directory ../elsewhere che dice" il nome 'Betty.txt' è associato ai dati che possono essere trovati tramite l'inode ####### ". Questo è il motivo per cui puoi "spostare" un file da 2 gigabyte con la stessa velocità di un file da 2 kilobyte, purché tu li sposti in un'altra posizione sulla stessa unità.]

Poiché il sistema operativo deve tenere traccia del numero di voci di directory diverse che puntano allo stesso blocco di dati, è possibile sapere se un determinato file è stato collegato in modo rigido, anche se non si può dire con certezza se la voce di directory che si stai guardando è quello "originale" o no. Un modo è il comando "ls", in particolare "ls -l" (che è una L minuscola dopo il trattino)

Per prendere in prestito un esempio precedente ....

 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1

La prima lettera è un trattino, quindi non è una directory o qualcos'altro esotico, è un file ordinario "normale". Ma se fosse veramente ordinario, quel numero dopo la parte rwx-ish sarebbe "1", come in "c'è una voce di directory che punta a questo blocco di dati". Ma fa parte di una dimostrazione di collegamenti reali, quindi dice "3".

Nota che questo può eventualmente portare a comportamenti strani e misteriosi (se non hai avvolto la testa attorno a collegamenti duri, cioè). Se apri Fred.txt nel tuo editor di testo e apporti alcune modifiche, vedrai le stesse modifiche in Wilma.txt e Barney.txt? Può essere. Probabilmente. Se l'editor di testo salva le modifiche aprendo il file originale e scrivendone le modifiche, sì, tutti e tre i nomi rimarranno comunque puntati sullo stesso testo (appena modificato). Ma se il tuo editor di testo crea un nuovo file (Fred-new-temp.txt), scrive la versione modificata in quella versione, quindi elimina Fred.txt, quindi rinomina Fred-new-temp.txt in Fred.txt, Wilma e Barney lo faranno punta ancora alla versione originale, non alla nuova versione modificata. Se non capisci gli hard link, questo potrebbe farti impazzire leggermente. :) [Okay, non ne conosco personalmente nessunoeditor di testo che farebbero il nuovo file / rinominino, ma conosco molti altri programmi che fanno esattamente questo, quindi state attenti.]

Un'ultima nota: una delle cose che 'fsck' (controllo del file system) verifica è se ci sono blocchi di dati sul disco che in qualche modo non fanno più riferimento a nessuna voce della directory. A volte qualcosa va storto e l'unica voce della directory che punta a un inode viene eliminata ma lo spazio sul disco stesso non viene contrassegnato come "disponibile". Quindi uno dei lavori di fsck è quello di far corrispondere tutto lo spazio allocato con tutte le voci della directory per assicurarsi che non ci siano file senza riferimento. Se ne trova alcune, crea nuove voci di directory e le inserisce in "lost + found".


Mi chiedo, quali sono quegli "altri programmi che fanno esattamente questo"?
phk,

@phk Non so a cosa stia pensando in modo specifico, ma questo è un approccio abbastanza comune per fare azioni che possono richiedere molto tempo e ti lasceranno in uno stato incerto se fallito. Ad esempio, se provi a scaricare da un server remoto e sai che esiste la possibilità che il server possa andare in timeout, un approccio sarebbe quello di scaricare l'intero contenuto in un file temporaneo. In questo modo se qualcosa va storto con il download hai ancora il file originale.
cwallenpoole,

L'unico programma che conosco per certo è FreeHand, perché se / quando si blocca durante un salvataggio, c'è un file temporaneo lasciato, piuttosto che un file originale alterato. Ma ho visto farlo anche altri programmi; Non posso darti esempi specifici in questo momento.
Snarke,

2

puoi usare readlink FILE; echo $?. Ciò restituisce 1 quando è un collegamento fisico e 0 quando è un collegamento simbolico.

Dalla pagina man: "Quando viene invocato come readlink, viene stampato solo il target del link simbolico. Se l'argomento dato non è un link simbolico, readlink non stampa nulla e termina con un errore."

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.