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

Hoe kun je de echte harde link zien door ls?

Ik draai

ln /a/A /b/B

Ik zou graag in de map a willen zien waar het bestand A naar toe wijst door ls.

Antwoorden (9)

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

U kunt vinden inode nummer voor uw bestand met

ls -i

en

ls -l

toont verwijzingen tellen (aantal hardlinks naar een bepaalde inode)

nadat u gevonden inode nummer, kunt u zoeken naar alle bestanden met dezelfde inode:

find . -inum NUM

toont bestandsnamen voor inode NUM in huidige dir (.)

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

Er is niet echt een duidelijk antwoord op je vraag. In tegenstelling tot symlinks, zijn hardlinks niet te onderscheiden van het “originele bestand”.

Directory entries bestaan uit een bestandsnaam en een pointer naar een inode. De inode bevat op zijn beurt de metadata van het bestand en (pointers naar) de eigenlijke bestandsinhoud). Het maken van een hard link creëert een andere bestandsnaam + verwijzing naar dezelfde inode. Deze referenties zijn unidirectioneel (in typische bestandssystemen, tenminste) – de inode houdt alleen een referentietelling bij. Er is geen intrinsieke manier om uit te vinden wat de “originele” bestandsnaam is.

Tussen haakjes, dit is waarom de system call om een bestand te “verwijderen” unlink heet. Het verwijdert alleen een hardlink. De inode en de bijbehorende gegevens worden alleen verwijderd als het aantal verwijzingen naar de inode tot 0 is gedaald.

De enige manier om de andere verwijzingen naar een gegeven inode te vinden is door het bestandssysteem uitputtend te doorzoeken om te zien welke bestanden naar de inode in kwestie verwijzen. U kunt ‘test A -ef B’ vanuit de shell gebruiken om deze controle uit te voeren.

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

De eerste kolom geeft de permissies weer. De tweede kolom is het aantal sub-items (voor directories) of het aantal paden naar dezelfde gegevens (hard links, inclusief het originele bestand) naar het bestand. Bijv:

-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

Wat dacht je van de volgende eenvoudigere? (De laatste zou de lange scripts hierboven kunnen vervangen!)

Als je een specifiek bestand hebt <THEFILENAME>en je wilt alle hardlinks daarvan weten verspreid over de directory <TARGETDIR>, (die zelfs het hele bestandssysteem kan zijn dat wordt aangeduid met /)

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

De logica uitbreiden, als je alle bestanden wilt weten in de <SOURCEDIR> met meerdere hardlinks verspreid over <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

Er zijn veel antwoorden met scripts om alle hardlinks in een bestandssysteem te vinden. De meeste van hen doen domme dingen zoals het uitvoeren van find om het hele bestandssysteem te scannen op -samefile voor ELK meervoudig gelinkt bestand. Dit is gekkenwerk; je hoeft alleen maar op inode nummer te sorteren en duplicaten te printen.

Met slechts één pass over het bestandssysteem om alle sets van hard-gekoppelde bestanden te vinden en te groeperen

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

Dit is veel sneller dan de andere antwoorden voor het vinden van meerdere sets van hard-gekoppelde bestanden.
find /foo -samefile /bar is uitstekend voor slechts één bestand.

  • -xdev : beperken tot één bestandssysteem. Niet strikt noodzakelijk omdat we ook de FS-id naar uniq printen op
  • ! -type d afgewezen directories: de . en .. entries betekenen dat ze altijd gelinkt zijn.
  • -links +1 : link count strikt > 1
  • -printf ... FS-id, inode nummer, en pad afdrukken. (Met padding tot vaste kolombreedtes waarover we uniq kunnen vertellen.)
  • sort -n | uniq ... numeriek sorteren en uniquify op de eerste 42 kolommen, groepen scheidend met een lege regel

! -type d -links +1 gebruiken betekent dat de invoer van sort slechts zo groot is als de uiteindelijke uitvoer van uniq, zodat we niet een enorme hoeveelheid string-sortering doen. Tenzij je het uitvoert op een subdirectory die slechts één van een set hardlinks bevat. Hoe dan ook, dit zal VEEL minder CPU-tijd gebruiken om het bestandssysteem opnieuw te doorlopen dan elke andere geposte oplossing.

voorbeeld uitvoer:

...
            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?: maak de uitvoer on-pad met awk of cut. uniq heeft zeer beperkte veld-selectie ondersteuning, dus ik pad de find output en gebruik fixed-width. 20 karakters is breed genoeg voor het maximaal mogelijke inode- of apparaatnummer (2^64-1 = 18446744073709551615). XFS kiest inode-nummers gebaseerd op waar op de schijf ze worden toegewezen, niet contigu vanaf 0, dus grote XFS bestandssystemen kunnen inode-nummers van >32bit hebben, zelfs als ze geen miljarden bestanden hebben. Andere bestandssystemen kunnen 20-cijferige inode nummers hebben, zelfs als ze niet gigantisch zijn.

TODO: sorteer groepen van duplicaten op pad. Door ze te sorteren op mount-punt en dan op inode-nummer worden dingen door elkaar gehaald, als je een paar verschillende subdirs hebt die veel hardlinks hebben. (d.w.z. groepen dup-groepen gaan samen, maar de uitvoer haalt ze door elkaar).

Een laatste sort -k 3 zou regels apart sorteren, niet groepen van regels als een enkel record. Voorbewerken met iets om een paar nieuwe regels om te zetten in een NUL byte, en GNU sort --zero-terminated -k 3 gebruiken zou kunnen werken. tr werkt echter alleen op enkele karakters, niet op 2-[1] of 1-[2] patronen. perl zou het kunnen doen (of gewoon parsen en sorteren in perl of awk). sed zou ook kunnen werken.

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

Dit is een beetje een commentaar op Torocoro-Macho’s eigen antwoord en script, maar het past natuurlijk niet in het commentaarvak.

  • *

Herschreef je script met meer eenvoudige manieren om de info te vinden, en dus een stuk minder procesaanroepen.

#!/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

Ik heb geprobeerd het zo veel mogelijk op dat van jou te laten lijken om het makkelijk te kunnen vergelijken.

Commentaar op dit script en het jouwe

  • Je moet altijd de $IFS magie vermijden als een glob volstaat, omdat het onnodig ingewikkeld is, en bestandsnamen eigenlijk newlines kunnen bevatten (maar in de praktijk meestal de eerste reden).

  • Je moet het handmatig parsen van ls en dergelijke uitvoer zo veel mogelijk vermijden, omdat het je vroeg of laat zal bijten. Bijvoorbeeld: in je eerste awk regel, faal je op alle bestandsnamen die spaties bevatten.

  • printf zal uiteindelijk vaak problemen besparen, omdat het zo robuust is met de %s syntax. Het geeft je ook volledige controle over de uitvoer, en is consistent over alle systemen, in tegenstelling tot echo.

  • stat kan je in dit geval een hoop logica besparen.

  • GNU find is krachtig.

  • Je head en tail aanroepingen hadden direct in awk afgehandeld kunnen worden met b.v. het exit commando en/of het selecteren op de NR variabele. Dit zou proces aanroepen besparen, wat bijna altijd de performance sterk verbetert in hard-werkende scripts.

  • Je egreps zouden net zo goed gewoon grep kunnen zijn.

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

Gebaseerd op het findhardlinks script (hernoemd naar hard-links), is dit wat ik heb gerefactored en het werkend heb gemaakt.

Uitgang:

# ./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

Een GUI oplossing komt heel dicht bij je vraag:

Je kunt de eigenlijke hardlinked bestanden van “ls” niet opnoemen omdat, zoals eerdere commentatoren al aangaven, de bestands “namen” slechts aliassen zijn naar dezelfde gegevens. Er is echter een GUI programma dat heel dicht in de buurt komt van wat u wilt, namelijk een padlijst weergeven van bestandsnamen die naar dezelfde gegevens wijzen (als hardlinks) onder linux, het heet FSLint. De optie die u zoekt staat onder “Name clashes” -> deselecteer “checkbox $PATH” in Search (XX) -> en selecteer “Aliases” uit de drop-down box na “for…” in het midden bovenaan.

FSLint is zeer slecht gedocumenteerd, maar ik heb ontdekt dat als je ervoor zorgt dat de beperkte mapstructuur onder “Zoek pad” met het selectievakje geselecteerd voor “Recurse?” en de eerder genoemde opties, een lijst van hardlinked gegevens met paden en namen die “wijzen” naar dezelfde gegevens worden geproduceerd nadat het programma zoekt.

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

Je kunt ls instellen om hardlinks te markeren met een ‘alias’, maar zoals eerder gezegd is er geen manier om de ‘bron’ van de hardlink te tonen, daarom voeg ik .hardlink toe om daarbij te helpen.

Voeg het volgende toe ergens in je .bashrc

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