Asıl sabit bağlantıyı ls ile nasıl görebilirsiniz?


97

koşarım

ln /a/A /b/B

aA dosyasının işaret ettiği klasörü görmek isterim ls.


1
Sabit bağlantılar işaretçi değildir, sembolik bağlantılar vardır. Aynı dosya için birden fazla isim var (inode). Bir link(2)sistem çağrısından sonra , hangisinin orijinal ve diğeri bağlantı olduğu hiçbir anlamı yoktur. Bu nedenle, cevapların işaret ettiği gibi, tüm bağlantıları bulmanın tek yolu budur find / -samefile /a/A. Çünkü bir inode için bir dizin girişi aynı inode için diğer dizin girişlerini "bilmez". Yaptıkları tek şey inode'yu yeniden saymak, böylece soyadı ne zaman silinebiliyor unlink(2)ed. (Bu lsçıktıdaki "link sayısı" dır ).
Peter Cordes

@PeterCordes: Refcount aslında hardlink girişinde saklanıyor mu? İfadelerinizin ima ettiği şey budur ("Yaptıkları tek şey inode'u yeniden saymaktır ...") Fakat eğer bağlantılar birbirleriyle ilgili hiçbir şey bilmiyorsa, bu bir güncelleme yapıldığında diğerlerinin bir şekilde yapması gerektiğinden, bu anlamlı olmaz. güncellenecek. Yoksa refcount inode'da mı saklanıyor? (Aptalca bir soru ise, beni affet, kendimi bir acemi olarak görüyorum ve hala öğreniyorum).
loneboat

1
Geri sayım sonunda diğer olgularda olduğu gibi, sonunda düşündüğünüz gibi inode içinde saklanır. :) Dizin girişleri, inode'lara işaretçiler olarak adlandırılır. Aynı inode'u gösteren birden fazla isminiz varsa buna "hard link" diyoruz.
Peter Cordes,

Yanıtlar:


171

Dosyanızın inode numarasını bulabilirsiniz.

ls -i

ve

ls -l

referans sayısını gösterir (belirli bir inode'a verilen hardlinks sayısı)

inode numarasını bulduktan sonra, aynı inode'a sahip tüm dosyaları arayabilirsiniz:

find . -inum NUM

NUM inode için dosya isimleri geçerli dir (.) 'de


46
sadece bulmaya çalışabilirsin. -samefile dosyaadı
BeowulfNode42

1
@ BeowulfNode42 Bu komut harika, ancak en azından aynı dosyaların paylaşılan kök klasörüne ihtiyacı var.
Itachi

1
bu cevap pragmatik bir "bunu yap" verir, ancak @LaurenceGonsalves'in "nasıl" ve / veya "neden" sorularına cevap verdiğini şiddetle hissediyorum .
Trevor Boyd Smith

65

Sorunuza gerçekten iyi tanımlanmış bir cevap yok. Sembolik bağlantılardan farklı olarak, hardlinks "orijinal dosyadan" ayırt edilemez.

Dizin girişleri bir dosya adından ve bir inode için bir işaretçiden oluşur. Sırayla inode, dosya meta verilerini ve (işaretçilere gerçek dosya içeriğini gösterir). Bir sabit link oluşturmak, aynı inode için başka bir dosya adı + referansı oluşturur. Bu referanslar tek yönlüdür (tipik dosya sistemlerinde, en azından) - inode yalnızca referans sayısını tutar. Hangisinin "orijinal" dosya adının olduğunu bulmanın hiçbir içsel yolu yoktur.

Bu arada, sistem bir çağrının "silmek" için çağrılmasının nedeni budur unlink. Sadece bir hardlink kaldırır. İnode eklenmiş bir veri sadece inode referans sayısı 0'a düşerse silinir.

Belirli bir inode için diğer referansları bulmanın tek yolu, hangi dosyaların söz konusu inode'a başvurduğunu kontrol eden dosya sistemi üzerinde kapsamlı bir şekilde arama yapmaktır. Bu kontrolü yapmak için kabuktan 'test A -ef B' kullanabilirsiniz.


35
Bunun anlamı , orijinal dosya aynı zamanda bir bağlantı olduğu için başka bir dosyaya bağlantı vermek gibi bir şey yoktur ; Sabit bağlantılar , diskteki bir konuma işaret eder .
jtbandes

12
@jtbandes: Sabit bağlantılar gerçek verilere işaret eden bir inode'u gösterir.
dash17291,

33

UNIX'in sabit bağlantıları ve sembolik bağlantıları vardır ( sırasıyla "ln"ve ile yapılır "ln -s"). Sembolik bağlantılar, basit bir şekilde başka bir dosyanın gerçek yolunu içeren ve dosya sistemlerini geçebilen bir dosyadır.

Sabit bağlantılar, UNIX'in ilk günlerinden beri (zaten hatırlayabildiğimden beri ve bu bir süre geri gidiyor) olmuştur. Onlar başvuran iki dizin girişleri olan tam aynı temel verileri. Bir dosyadaki veriler onun tarafından belirtilir inode. Bir dosya sistemindeki her dosya bir inode'yu işaret eder, ancak her dosyanın benzersiz bir inode'a işaret etmesi gerekmez - bu, zor bağlantıların geldiği yerdir.

İnode'lar yalnızca belirli bir dosya sistemi için benzersiz olduğundan, sabit bağlantıların aynı dosya sisteminde olması zorunludur (sembolik bağlantıların aksine). Sembolik bağların aksine, ayrıcalıklı bir dosya olmadığına - hepsinin eşit olduğuna dikkat edin. Veri alanı, yalnızca bu inode'u kullanan tüm dosyalar silindiğinde serbest bırakılacaktır (ve tüm işlemler onu kapatır, ancak bu farklı bir konudur).

"ls -i"Komutu belirli bir dosyanın inode'unu almak için kullanabilirsiniz . "find <filesystemroot> -inum <inode>"Komutu, dosya sistemindeki tüm dosyaları verilen inode ile bulmak için kullanabilirsiniz .

İşte tam olarak bunu yapan bir senaryo. Şunu çağırdın:

findhardlinks ~/jquery.js

ve o dosya sistemi için, o dosya için bağlantı kuran tüm dosyaları bulacaktır:

pax@daemonspawn:~# ./findhardlinks /home/pax/jquery.js
Processing '/home/pax/jquery.js'
   '/home/pax/jquery.js' has inode 5211995 on mount point '/'
       /home/common/jquery-1.2.6.min.js
       /home/pax/jquery.js

İşte senaryo.

#!/bin/bash
if [[ $# -lt 1 ]] ; then
    echo "Usage: findhardlinks <fileOrDirToFindFor> ..."
    exit 1
fi

while [[ $# -ge 1 ]] ; do
    echo "Processing '$1'"
    if [[ ! -r "$1" ]] ; then
        echo "   '$1' is not accessible"
    else
        numlinks=$(ls -ld "$1" | awk '{print $2}')
        inode=$(ls -id "$1" | awk '{print $1}' | head -1l)
        device=$(df "$1" | tail -1l | awk '{print $6}')
        echo "   '$1' has inode ${inode} on mount point '${device}'"
        find ${device} -inum ${inode} 2>/dev/null | sed 's/^/        /'
    fi
    shift
done

@ Pax: Senaryoda bir hata var gibi görünüyor. . ./findhardlinks.bashOS X’in Zsh’ındayken başlıyorum . Ekrandaki geçerli pencerem kapanıyor.

4
@Masi Sorun sizin başlangıçınız. (kaynak komutla aynı). Bu, exit 1 komutunun kabuğunuzdan çıkmasına neden olur. Chmod a + x findhardlinks.bash kullanın, sonra ./findhardlinks.bash ile çalıştırın veya bash findhardlinks.bash kullanın
njsf


3
Bunun yerine bu kullanırsanız programlı Bunu yapmak için, muhtemelen daha esnek bulunuyor: INUM=$(stat -c %i $1). Ayrıca NUM_LINKS=$(stat -c %h $1). man statKullanabileceğiniz daha fazla format değişkeni için görün .
Joe

Şimdiye kadar en iyi cevap. Kudos.
MariusMatutiae

24
ls -l

İlk sütun izinleri temsil edecektir. İkinci sütun, alt öğelerin sayısı (dizinler için) veya dosyaya aynı verilere giden yolların sayısı (orijinal dosya dahil olmak üzere sabit bağlantılar) olacaktır. Örneğin:

-rw-r--r--@    2    [username]    [group]    [timestamp]     HardLink
-rw-r--r--@    2    [username]    [group]    [timestamp]     Original
               ^ Number of hard links to the data

2
Belirli bir dosyanın [diğer] sert bağlantıları varsa IF'nin belirlenmesinde yardımcı olur, ancak NEREDE OLDUĞUNDAN.
mklement0

Ayrıca, hard link ile orijinal dosya arasında teknik bir ayrım yoktur. İkisi de aynıdır, sadece inodehangisinin disk içeriğini gösterdiğine işaret eder.
guyarad

13

Aşağıdaki daha basit olana ne dersiniz? (İkincisi, yukarıdaki uzun komut dosyalarının yerini alabilir!)

Belirli bir dosyanız varsa <THEFILENAME>ve dizine yayılmış olan tüm hardlinks bağlantılarını bilmek istiyorsanız <TARGETDIR>, (ki bu, tüm sistem tarafından bile belirtilebilir /)

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

<SOURCEDIR>Birden fazla sabit bağlantıya sahip tüm dosyaları bilmek istiyorsanız, mantığı genişletme <TARGETDIR>:

find <SOURCEDIR> -type f -links +1   \
  -printf "\n\n %n HardLinks of file : %H/%f  \n"   \
  -exec find <TARGETDIR> -type f -samefile {} \; 

Bu benim için en iyi cevap! ancak ben de kullanmam -type fçünkü dosya da bir dizin olabilir.
Silvio,

3
@ silvio: Dizinlere değil sadece dosyalara zor linkler oluşturabilirsiniz .
mklement0

@ mklement0: Haklısın!
Silvio

.Ve ..dizinleri girişler hardlinks bulunmaktadır. Bir dizinde kaç tane alt dizin olduğunu, link sayısından öğrenebilirsiniz .. Yine de find -samefile .herhangi bir subdir/..çıktı yazdırmayacağından , bu durum yine de tartışmalı . find(en azından GNU versiyonu) ..bile olsa görmezden gelmek zor kodlanmış görünüyor -noleaf.
Peter Cordes

Ayrıca, bu tüm bağlantıları bulma fikri, bir dizi sabitlenmiş dosyanın her üyesi için bir kez O(n^2)çalışır ve çalışır find. find ... -printf '%16i %p\n' | sort -n | uniq -w 16 --all-repeated=separateçalışacak, (16, 2 ^ 63-1 ondalık gösterimi için yeterince geniş değil, bu yüzden XFS dosya sisteminiz çok yüksek inode sayılarına sahip olacak kadar büyük olduğunda, dikkat edin)
Peter Cordes 21:05

5

Bir dosya sistemindeki tüm sabit bağlantıları bulmak için komut dosyalarıyla ilgili birçok cevap vardır. Birçoğu çalışan gibi aptalca şeyler yaparlar -samefile, EACH çarpı bağlantılı dosyanın tüm dosya sistemini taramak için . Bu çılgınca; İhtiyacınız olan tek şey inode numarasını sıralamak ve kopyaları yazdırmak.

Tüm hardlinked dosya setlerini bulmak ve gruplandırmak için sadece bir dosya sistemi üzerinden geçiş

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

Bu, çok sayıda hardlinked dosya kümesi bulmak için diğer cevaplardan çok daha hızlıdır .
find /foo -samefile /barsadece bir dosya için mükemmel.

  • -xdev: bir dosya sistemi ile sınır. FS-id'i uniq on olarak da yazdığımızdan kesinlikle gerek yok.
  • ! -type ddizinleri reddetme: .ve ..girişleri her zaman bağlantılı oldukları anlamına gelir.
  • -links +1 : bağlantı kesinlikle > 1
  • -printf ...FS kimliği, inode numarası ve yolu yazdır. (Söyleyebileceğimiz sabit sütun genişliklerine dolguyla uniq.)
  • sort -n | uniq ... nümerik sıralama ve ilk 42 sütunda birleştirme, grupları boş bir çizgiyle ayırma

Kullanma ! -type d -links +1, sıralama girişinin yalnızca uniq'in son çıktısı kadar büyük olduğu anlamına gelir, bu nedenle çok fazla miktarda dize işlemi yapmıyoruz. Tabi yalnızca bir dizi hardlinks içeren bir alt dizinde çalıştırmazsanız. Neyse, bu dosya sisteminde dolaşan diğer tüm çözümlerden daha az LOT daha az CPU zamanı kullanacak.

örnek çıktı:

...
            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 ?: çıktıyı awkveya ile açın cut. uniqAlan seçimi desteği çok sınırlı, bu yüzden bulma çıktısını dolduruyorum ve sabit genişlikte kullanıyorum. 20char, mümkün olan maksimum inode veya cihaz numarası için yeterince geniştir (2 ^ 64-1 = 18446744073709551615). XFS, diskte nereye yerleştirildiğine bağlı olarak inode sayılarını seçer, 0'dan bitişik değil, bu yüzden büyük XFS dosya sistemlerinde milyarlarca dosya olmasa bile> 32bit inode numaralarına sahip olabilir. Diğer dosya sistemlerinde devasa olmasalar bile 20 basamaklı inode numaraları bulunabilir.

TODO: yinelenen grupları yola göre sırala. Bunları bağlama noktasına göre sıraladıktan sonra inode numarası, çok sayıda sabit bağlantı içeren birkaç farklı alt diziniz varsa, bunları bir araya getirir. (yani, dup grup grupları bir araya gelirler, fakat çıktı onları karıştırır).

Bir son sort -k 3satır, satır gruplarını tek bir kayıt olarak değil, satırları ayrı ayrı sıralar. Bir çift yeni satırı bir NUL baytına dönüştürecek bir şeyle ön işleme koymak ve GNU kullanmak sort --zero-terminated -k 3hile yapabilir. tr2 -> 1 veya 1-> 2 kalıpları değil, yalnızca tek karakterlerde çalışır. perlbunu yapardı (veya sadece perl veya awk içinde ayrıştırır ve sıralarlar). sedayrıca çalışabilir.


1
%DDosya sistemi tanıtıcısı (hiçbir dosya sistemleri ise o geçerli önyükleme için benzersiz olduğunu umount, bu nedenle aşağıdaki daha genel ed) 'dir: find directories.. -xdev ! -type d -links +1 -printf '%20i %20D %p\n' | sort -n | uniq -w 42 --all-repeated=separate. Bu, hiçbir dizinin dosya sistemi düzeyinde başka bir dizin içermediği sürece çalışır, aynı zamanda sabitlenmiş olabilecek her şeye bakar (cihazlar veya yazılım bağlantıları - evet, yazılım bağlantıları 1'den büyük bir bağlantı sayısına sahip olabilir). dev_tVe ino_tbugün 64 bit uzun olduğuna dikkat edin . Bu olasılık 64 bit sistemimiz olduğu sürece geçerli olacak.
Tino,

@Tino: ! -type dyerine kullanmanın kullanımıyla ilgili harika bir nokta -type f. Hatta dosya sistemimde bazı dosya koleksiyonları düzenlemekten bazı sabit linkler bile var. Cevabınızı gelişmiş sürümünüzle güncelledik (ama önce fs-id'yi koydum, bu yüzden sıralama düzeni en azından dosya sistemine göre gruplandı.)
Peter Cordes

3

Bu, Torocoro-Macho'nun kendi cevabı ve senaryosuna yapılan bir yorumdan kaynaklanıyor, ancak kesinlikle yorum kutusuna sığmayacak.


Komut dosyanızı bilgileri bulmak için daha basit yollarla ve böylece daha az işlem çağrısı ile yeniden yazdınız.

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

Kolay karşılaştırma için olabildiğince benzer tutmaya çalıştım.

Bu senaryo ve sizinkine yorumlar

  • $IFSEğer bir glob yeterse, sihirden kaçınılmalıdır , çünkü gereksiz yere kıvrımlıdır ve dosya isimleri aslında yeni satırlar içerebilir (fakat uygulamada çoğunlukla birinci sebep).

  • El ile ayrıştırmaktan lsve bu tür çıktılardan mümkün olduğu kadar kaçınmalısınız , çünkü er ya da geç ısırır. Örneğin: ilk awksatırınızda boşluk içeren tüm dosya adlarında başarısız olursunuz.

  • printf%sSözdizimi ile çok sağlam olduğu için sık sık sonunda sıkıntıları kurtaracak . Ayrıca, çıktı üzerinde tam kontrol sağlar ve aksine, tüm sistemler arasında tutarlıdır echo.

  • stat Bu durumda size çok fazla mantık kazandırabilir.

  • GNU find güçlü.

  • Siz headve tailçağrılarınız awk, örneğin exitkomut ve / veya NRdeğişkeni seçerek doğrudan ele alınabilirdi . Bu, neredeyse her zaman ciddi şekilde çalışan komut dosyalarında daha iyi performans gösteren betimleme işlemlerini koruyacaktır.

  • Senin egrepde olabildiğince iyi olabilir grep.


xDEVICE = $ (stat -c% m "$ {xFILE}") tüm sistemlerde çalışmıyor (örneğin: stat (GNU coreutils) 6.12). Komut dosyası "Öğe:?" Her satırın başında, bu rahatsız edici çizgiyi orijinal komut dosyası gibi bir satırla değiştirin, ancak xITEM ile xFILE olarak yeniden adlandırıldı: xDEVICE = $ (df "$ {xFILE}" | tail -1l | awk '{print $ 6} ')
kbulgrien

Sadece "ana" olarak her bir üye ile tekrarlanmak yerine, hardlinks gruplarını istiyorsanız, kullanın find ... -xdev -type f -links +1 -printf '%16i %p\n' | sort -n | uniq -w 16 --all-repeated=separate. Bu sadece bir kerelik fs geçerken ÇOK daha hızlı. Aynı anda birden fazla FS için, inode numaralarını bir FS kimliği ile öneklemeniz gerekir. Belki defind -exec stat... -printf ...
Peter Cordes

bu fikri bir cevaba çevirdi
Peter Cordes

2

findhardlinksSenaryoya göre (yeniden adlandırılmış hard-links), yeniden düzenledim ve çalışmasını sağladım.

Çıktı:

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

Bu komut dosyası için ayrı bir cevap olarak yorum yaptım.
Daniel Andersson

1

Bir GUI çözümü sorunuza gerçekten yaklaşıyor:

Asıl sabitlenmiş dosyaları "ls" den listeleyemezsiniz, çünkü önceki yorumcuların işaret ettiği gibi, "names" dosyası aynı verinin diğer adıdır. Bununla birlikte, gerçekte istediklerinize gerçekten yaklaşan bir GUI aracı vardır ki bu linux altında aynı verilere (hardlinks gibi) işaret eden dosya adlarının yol listesini görüntüler, buna FSLint denir. İstediğiniz seçenek "Ad çakışmaları" -> Arama (XX) -> 'daki "onay kutusu $ PATH" seçeneğinin işaretini kaldırın ve açılır kutudan "for ..." dan sonra üst ortaya doğru "Aliases" ı seçin.

FSLint çok kötü bir şekilde belgelenmiştir ancak "Arama yolu" altındaki sınırlı dizin ağacının "Tekrarla?" ve yukarıda belirtilen seçeneklerde, program araştırmasından sonra, aynı veriye işaret eden yollar ve isimlerle bağlantılı, sabitlenmiş verilerin bir listesi üretilir.



1

lsBir 'takma ad' kullanarak sabit bağlantıları vurgulamak için yapılandırabilirsiniz , ancak daha önce de belirtildiği gibi, hardlink'in kaynağını göstermenin bir yolu yoktu, bu yüzden bu konuda .hardlinkyardımcı olmayı düşünüyorum.

hardlinks vurgulamak

Aşağıdakileri telefonunuzda bir yere ekleyin. .bashrc

alias ll='LC_COLLATE=C LS_COLORS="$LS_COLORS:mh=1;37" ls -lA --si --group-directories-first'
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.