it-swarm-tr.com

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

Koşarım

ln /a/A /b/B

a klasöründe A dosyasının ls işaret ettiği yerde görmek istiyorum.

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

şu anki dizinde NUM inode için dosya isimlerini gösterecek.

162
zzr

Sorunuza gerçekten iyi tanımlanmış bir cevap yok. Sembolik bağlantılardan farklı olarak, hardlinkler "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 dosyayı "silmek" için çağrılmasının unlink olarak adlandırılmasının nedeni budur. 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ü gerçekleştirmek için Shell'den 'test A -ef B'yi kullanabilirsiniz.

59

UNIX'in sabit bağlantıları ve sembolik bağlantıları vardır (sırasıyla "ln" ve "ln -s" ile yapılmıştır). 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. Bunlar, kesin aynı temel verilere başvuran iki dizin girdisidir. Bir dosyadaki veriler inode tarafından belirtilir. Bir dosya sistemindeki her dosya bir inode'yu işaret eder, ancak her dosyanın benzersiz bir inode'a işaret etmesi gerekmez - bu da 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 tümü bu inode'u kullanan dosyalar silindiğinde serbest bırakılacaktır (ve tüm işlemler onu kapatır, ancak bu farklı bir konudur).

Belirli bir dosyanın inode'unu almak için "ls -i" komutunu kullanabilirsiniz. Ardından, dosya sistemindeki tüm dosyaları verilen inode ile bulmak için "find <filesystemroot> -inum <inode>" komutunu 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:

[email protected]:~# ./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
33
user53528
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:

[email protected]    2    [username]    [group]    [timestamp]     HardLink
[email protected]    2    [username]    [group]    [timestamp]     Original
               ^ Number of hard links to the data
24
eyelidlessness

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

Belirli bir <THEFILENAME> dosyasına sahipseniz ve <TARGETDIR> dizini üzerine yayılan tüm bağlantılarını bilmek istiyorsanız (/ ile belirtilen tüm dosya sistemi bile olabilir)

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

<SOURCEDIR> 'daki tüm dosyaları <TARGETDIR> üzerine yayılmış çok sayıda sabit bağlantı içeren bilmek istiyorsanız, mantığı genişletme:

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

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

find directories.. -xdev ! -type d -links +1 -printf '%20D %20i %p\n' | sort -n | uniq -w 42 --all-repeated=separate (Bir FS kimliğini (%D) desteklemek için orjinal komutumu değiştirmek için @Tino'ya teşekkür ederiz ve sadece normal dosyaları değil tüm dizin olmayan dosya türlerini idare eder.

! -type d -links +1 kullanmak, sort girişinin yalnızca uniq'in son çıktısı kadar büyük olduğu anlamına gelir. 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ının kilidini açın. uniq, alan seçim desteğini çok kısıtlıyor, bu yüzden find çıkışını dolduruyorum ve sabit genişlik 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ı bunları karıştırır).

Son bir sort -k 3, satırları tek bir kayıt olarak değil, grupları ayrı ayrı sıralar. Bir çift yeni satırı NUL baytına dönüştürecek bir şeyle ön işlem yapmak ve GNU sort --zero-terminated -k 3 kullanmak hile yapabilir. tr, yalnızca 2-> 1 veya 1-> 2 desenlerinde değil, tek karakterlerde çalışır. Perl bunu yapar (veya sadece Perl veya awk içinde ayrıştırır ve sıralar). sed da işe yarayabilir.

4
Peter Cordes

Bu, Torocoro-Macho'nun kendi cevabı ve senaryosuna yapılan bir yorumdan kaynaklanıyor, ancak açıkçası 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

  • Bir glob yeterliyse, gereksiz yere kıvrımlı olduğundan ve dosya adları gerçekte yeni satırlar içerebildiğinden (ancak uygulamada çoğunlukla birinci neden) biri daima $IFS sihrinden kaçınmalıdır.

  • Er ya da geç ısırılacağından ls ve bu gibi çıktıların olabildiğince el ile ayrıştırılmasından kaçınmalısınız. Örneğin: ilk awk satırınızda boşluk içeren tüm dosya adlarında başarısız olursunuz.

  • printf, %s sözdizimine çok dayanıklı olduğu için sık sık sıkıntı yaratacaktır. Ayrıca çıktı üzerinde tam kontrol sağlar ve echo öğesinden farklı olarak all systems arasında tutarlıdır.

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

  • GNU find güçlüdür.

  • head ve tail çağrılarınız, örneğin awk'da doğrudan işlenebilirdi. exit komutu ve/veya NR değişkeninde seçim yapma. Bu, neredeyse her zaman ciddi şekilde çalışan komut dosyalarında daha iyi performans gösteren betimleme işlemlerini koruyacaktır.

  • egreps'niz sadece grep olabilir.

3
Daniel Andersson

findhardlinks betiğini temel alarak (onu hard-links olarak yeniden adlandırdı), 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 "";
2
Torocoro-Macho

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 Arama (XX) -> 'de "Ad çakışmaları" -> "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
Charles

Bir 'takma ad' kullanarak sabit bağlantıları vurgulamak için ls öğesini yapılandırabilirsiniz, ancak daha önce belirtildiği gibi, hardlink'in kaynağını göstermenin bir yolu yoktu, bu yüzden yardımcı olmak için .hardlink ekledim.

 highlight hardlinks

Aşağıdakileri .bashrc'nuzda bir yere ekleyin

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