2009-07-25 09:41:26 +0000 2009-07-25 09:41:26 +0000
104
104

Come si fa a vedere l'effettivo collegamento rigido tramite ls?

Eseguo

ln /a/A /b/B

vorrei vedere nella cartella a dove punta il file A da ls.

Risposte (9)

182
182
182
2009-07-25 10:01:32 +0000

Potete trovare il numero di inode per il vostro file con

ls -i

e

ls -l

mostra il numero di riferimenti (numero di hardlink a un particolare inode)

dopo aver trovato il numero di inode, potete cercare tutti i file con lo stesso inode:

find . -inum NUM

mostrerà i nomi dei file per inode NUM nella directory corrente (.)

66
66
66
2009-07-25 09:51:57 +0000

Non c'è una risposta ben definita alla tua domanda. A differenza dei symlink, gli hardlink sono indistinguibili dal “file originale”.

Le voci della directory consistono in un nome di file e un puntatore a un inode. L'inode a sua volta contiene i metadati del file e (puntatori al) contenuto effettivo del file). La creazione di un hard link crea un altro nome di file + riferimento allo stesso inode. Questi riferimenti sono unidirezionali (nei filesystem tipici, almeno) – l'inode mantiene solo un conteggio dei riferimenti. Non c'è un modo intrinseco per scoprire quale sia il nome del file “originale”.

A proposito, questo è il motivo per cui la chiamata di sistema per “cancellare” un file si chiama unlink. Rimuove solo un hardlink. L'inode e i dati collegati vengono cancellati solo se il numero di riferimenti all'inode scende a 0.

L'unico modo per trovare gli altri riferimenti a un dato inode è di cercare esaustivamente nel file system controllando quali file fanno riferimento all'inode in questione. Puoi usare ‘test A -ef B’ dalla shell per eseguire questo controllo.

24
24
24
2009-07-25 10:01:38 +0000
ls -l

La prima colonna rappresenterà i permessi. La seconda colonna sarà il numero di sotto-voci (per le directory) o il numero di percorsi per gli stessi dati (hard link, incluso il file originale) al file. Es:

-rw-r--r--@ 2 [username] [group] [timestamp] HardLink
-rw-r--r--@ 2 [username] [group] [timestamp] Original
               ^ Number of hard links to the data
14
14
14
2013-08-15 08:52:16 +0000

Che ne dite del seguente, più semplice? (Quest'ultima potrebbe sostituire i lunghi script di cui sopra!)

Se hai un file specifico <THEFILENAME>e vuoi conoscere tutti i suoi hardlink sparsi nella directory <TARGETDIR>, (che può anche essere l'intero filesystem indicato da /)

find <TARGETDIR> -type f -samefile <THEFILENAME>

Estendendo la logica, se vuoi conoscere tutti i file nella <SOURCEDIR> che hanno più hardlink sparsi su <TARGETDIR>:

find <SOURCEDIR> -type f -links +1 \
  -printf "\n\n %n HardLinks of file : %H/%f \n" \
  -exec find <TARGETDIR> -type f -samefile {} \;
6
6
6
2015-04-21 19:32:47 +0000

Ci sono molte risposte con script per trovare tutti gli hardlink in un filesystem. La maggior parte di loro fa cose stupide come eseguire find per scansionare l'intero filesystem per -samefile per OGNI file multiply-linked. Questo è folle; tutto ciò di cui avete bisogno è ordinare in base al numero di inode e stampare i duplicati.

Con un solo passaggio sul filesystem per trovare e raggruppare tutti i set di file hardlinked

find dirs -xdev \! -type d -links +1 -printf '%20D %20i %p\n' |
    sort -n | uniq -w 42 --all-repeated=separate

Questo è molto più veloce delle altre risposte per trovare più set di file hardlinked.
find /foo -samefile /bar è eccellente per un solo file.

  • -xdev : limitare a un solo filesystem. Non strettamente necessario dato che stampiamo anche l'FS-id a uniq su
  • ! -type d rifiuta le directory: le voci . e .. significano che sono sempre collegate.
  • -links +1 : conteggio dei link strettamente > 1
  • -printf ... stampa FS-id, numero di inode, e percorso. (Con il padding a larghezze di colonna fisse che possiamo comunicare a uniq.)
  • sort -n | uniq ... ordinamento numerico e univoco sulle prime 42 colonne, separando i gruppi con una linea vuota

Usare ! -type d -links +1 significa che l'input di sort è grande solo quanto l'output finale di uniq, quindi non stiamo facendo un'enorme quantità di ordinamento di stringhe. A meno che non lo eseguiate su una sottodirectory che contiene solo uno di una serie di hardlink. Comunque, questo userà molto meno tempo di CPU per attraversare nuovamente il filesystem rispetto a qualsiasi altra soluzione postata.

esempio di output:

...
            2429 76732484 /home/peter/weird-filenames/test/.hiddendir/foo bar
            2429 76732484 /home/peter/weird-filenames/test.orig/.hiddendir/foo bar

            2430 17961006 /usr/bin/pkg-config.real
            2430 17961006 /usr/bin/x86_64-pc-linux-gnu-pkg-config

            2430 36646920 /usr/lib/i386-linux-gnu/dri/i915_dri.so
            2430 36646920 /usr/lib/i386-linux-gnu/dri/i965_dri.so
            2430 36646920 /usr/lib/i386-linux-gnu/dri/nouveau_vieux_dri.so
            2430 36646920 /usr/lib/i386-linux-gnu/dri/r200_dri.so
            2430 36646920 /usr/lib/i386-linux-gnu/dri/radeon_dri.so
...

TODO?: disimpegna l'output con awk o cut. uniq ha un supporto molto limitato per la selezione dei campi, quindi imbottisco l'output di find e uso la larghezza fissa. 20 caratteri sono sufficienti per il massimo numero possibile di inode o di dispositivo (2^64-1 = 18446744073709551615). XFS sceglie i numeri di inode in base a dove sono allocati sul disco, non in modo contiguo da 0, quindi i grandi filesystem XFS possono avere numeri di inode di >32bit anche se non hanno miliardi di file. Altri filesystem potrebbero avere numeri di inode di 20 cifre anche se non sono giganteschi.

TODO: ordinare i gruppi di duplicati per percorso. Averli ordinati per punto di montaggio e poi per numero di inode confonde le cose, se si hanno un paio di sottodirectory diversi che hanno molti hardlink. (cioè i gruppi di dup-groups vanno insieme, ma l'output li mischia).

Un finale sort -k 3 ordinerebbe le linee separatamente, non gruppi di linee come un singolo record. La pre-elaborazione con qualcosa che trasformi una coppia di newline in un byte NUL, e l'uso di GNU sort --zero-terminated -k 3 potrebbe fare il trucco. tr opera solo su caratteri singoli, non su schemi 2->1 o 1->2, però. perl lo farebbe (o semplicemente analizzare e ordinare in perl o awk). Anche sed potrebbe funzionare.

3
3
3
2012-06-13 07:40:43 +0000

Questo è un po’ un commento alla risposta e allo script di Torocoro-Macho, ma ovviamente non ci sta nella casella dei commenti._


Riscrivere il tuo script con modi più diretti per trovare le informazioni, e quindi molte meno invocazioni di processo.

#!/bin/sh
xPATH=$(readlink -f -- "${1}")
for xFILE in "${xPATH}"/*; do
    [-d "${xFILE}"] && continue
    [! -r "${xFILE}"] && printf '"%s" is not readable.\n' "${xFILE}" 1>&2 && continue
    nLINKS=$(stat -c%h "${xFILE}")
    if [${nLINKS} -gt 1]; then
        iNODE=$(stat -c%i "${xFILE}")
        xDEVICE=$(stat -c%m "${xFILE}")
        printf '\nItem: %s[%d] = %s\n' "${xDEVICE}" "${iNODE}" "${xFILE}";
        find "${xDEVICE}" -inum ${iNODE} -not -path "${xFILE}" -printf ' -> %p\n' 2>/dev/null
    fi
done

Ho cercato di mantenerlo il più possibile simile al tuo per un facile confronto.

Commenti su questo script e sul tuo

  • Si dovrebbe sempre evitare la magia $IFS se basta un glob, poiché è inutilmente contorto, e i nomi dei file possono effettivamente contenere newline (ma in pratica soprattutto la prima ragione).

  • Dovresti evitare il più possibile di analizzare manualmente l'output di ls e simili, dato che prima o poi ti morderà. Per esempio: nella tua prima linea awk, fallisci su tutti i nomi di file che contengono spazi.

  • printf vi risparmierà spesso problemi alla fine, poiché è così robusto con la sintassi %s. Vi dà anche il pieno controllo sull'output, ed è coerente su tutti i sistemi, a differenza di echo.

  • stat può farvi risparmiare un sacco di logica in questo caso.

  • GNU find è potente.

  • Le tue invocazioni head e tail avrebbero potuto essere gestite direttamente in awk con ad esempio il comando exit e/o selezionando sulla variabile NR. Questo risparmierebbe le invocazioni di processo, il che migliora quasi sempre le prestazioni negli script che lavorano duramente.

  • I tuoi egrep potrebbero benissimo essere solo grep.

2
2
2
2011-11-16 22:46:38 +0000

Sulla base dello script findhardlinks (rinominato in hard-links), questo è ciò che ho rifatto e fatto funzionare.

Uscita:

# ./hard-links /root

Item: /[10145] = /root/.profile
    -> /proc/907/sched
    -> /<some-where>/.profile

Item: /[10144] = /root/.tested
    -> /proc/907/limits
    -> /<some-where else>/.bashrc
    -> /root/.testlnk

Item: /[10144] = /root/.testlnk
    -> /proc/907/limits
    -> /<another-place else>/.bashrc
    -> /root/.tested

 

# cat ./hard-links
#!/bin/bash
oIFS="${IFS}"; IFS=$'\n';
xPATH="${1}";
xFILES="`ls -al ${xPATH}|egrep "^-"|awk '{print $9}'`";
for xFILE in ${xFILES[@]}; do
  xITEM="${xPATH}/${xFILE}";
  if [[! -r "${xITEM}"]] ; then
    echo "Path: '${xITEM}' is not accessible! ";
  else
    nLINKS=$(ls -ld "${xITEM}" | awk '{print $2}')
    if [${nLINKS} -gt 1]; then
      iNODE=$(ls -id "${xITEM}" | awk '{print $1}' | head -1l)
      xDEVICE=$(df "${xITEM}" | tail -1l | awk '{print $6}')
      echo -e "\nItem: ${xDEVICE}[$iNODE] = ${xITEM}";
      find ${xDEVICE} -inum ${iNODE} 2>/dev/null|egrep -v "${xITEM}"|sed 's/^/ -> /';
    fi
  fi
done
IFS="${oIFS}"; echo "";
1
1
1
2015-01-20 18:00:05 +0000

Una soluzione GUI si avvicina molto alla tua domanda:

Non è possibile elencare gli effettivi file hardlinked da “ls” perché, come hanno sottolineato i commentatori precedenti, i “nomi” dei file sono semplici alias degli stessi dati. Tuttavia, c'è uno strumento GUI che si avvicina molto a quello che vuoi, cioè visualizzare un elenco di percorsi di nomi di file che puntano agli stessi dati (come hardlink) sotto linux, si chiama FSLint. L'opzione che vuoi è sotto “Name clashes” -> deseleziona “checkbox $PATH” in Search (XX) -> e seleziona “Alias” dalla casella a discesa dopo “for…” verso il centro in alto.

FSLint è molto poco documentato, ma ho scoperto che assicurandomi che l'albero delle directory limitato sotto “Percorso di ricerca” con la casella di controllo selezionata per “Ricorri?” e le suddette opzioni, un elenco di dati hardlinked con percorsi e nomi che “puntano” agli stessi dati sono prodotti dopo le ricerche del programma.

1
1
1
2017-12-06 17:34:25 +0000

Puoi configurare ls per evidenziare gli hardlink usando un ‘alias’, ma come detto prima non c'è modo di mostrare la ‘fonte’ dell'hardlink che è il motivo per cui aggiungo .hardlink per aiutare in questo.

Aggiungi il seguente da qualche parte nel tuo .bashrc

alias ll='LC_COLLATE=C LS_COLORS="$LS_COLORS:mh=1;37" ls -lA --si --group-directories-first'