Sabit bağlantıyı yerinde mi kırıyorsunuz?


13

Dotfiles'ımı sürüm denetimi altında tutuyorum ve onları dağıtan komut dosyası sabit bağlantılar oluşturur. Ben de etckeeperbenim /etcsürüm kontrolü koymak için kullanın . Son zamanlarda böyle uyarılar aldım:

warning: hard-linked files could cause problems with bzr

Basit bir kopya ( cp filename.ext filename.ext) çalışmaz:

cp: `filename.ext' and `filename.ext' are the same file

Birimin yeniden adlandırılması / taşınması - birimler dışında - ayrıca sabit bağlantıyı kesmez.

Benim sorum şu: aslında o dosyaya diğer sabit bağlantıların nerede olduğunu bilmek zorunda kalmadan bir dosyaya bir sabit bağlantı kırmak için bir yolu var mı?


2
"Rm" komutu sabit bağlantıları keser.
Johan

Yanıtlar:


14
cp -p filename filename.tmp
mv -f filename.tmp filename

Yazılabilir hale getirme:

dir=$(dirname -- "$filename")
tmp=$(TMPDIR=$dir mktemp)
cp -p -- "$filename" "$tmp"
mv -f -- "$tmp" "$filename"

Önce kopyanın yapılması, sonra yerine taşınması, dosyanın sabit bir bağlantı olmaktan ayrı bir kopya olmaktan atomik olarak değişmesi avantajına sahiptir (zamanın filenamekısmi veya eksik olduğu bir nokta yoktur ).


7

Muhtemelen sabit bağlantıyı ayrı, bağımsız bir dosyaya bölmek istediğinizi kastediyorsunuz.

mv hardlink tempname && cp tempname hardlink && rm tempname

Sabit bağlantı, dizindeki bir giriş ile diskteki inode bloğu arasındaki bağlantıdır.

inodes, dosya meta verilerini depolar ve küçük dosyalar için, bazı dosya sistemleri verileri inode'da saklar, aksi takdirde veri bloklarına işaret eder ve çok büyük dosyalar için dolaylı ve çift dolaylı işaretçi disk ayırma birimlerine listeler.

Ne olursa olsun, dosya adı (ls komutunun ürettiği şey) ve bu meta verileri depolayan inode bloğu arasındaki bağlantıya sabit bağlantı denir.

Tek bir dosyaya birden çok sabit bağlantıya sahip olmak, muhtemelen farklı dizinlerde (tek bir dosya sisteminde) birden fazla dizin girişi tarafından başvurulan aynı inode anlamına gelir.

rm dosya adı girişini dizinden siler. Bir inode'a artık herhangi bir dosya tarafından başvurulmadığında, alanı diğer dosyalar tarafından kullanılmak üzere serbest bırakılır.


Aslında. Bu nedir cpve mvörnekler ima etti. Yani geçici bir dosya kullanmanın bir yolu yok.
0xC0000022L

@ 0xC0000022L, Hayır, düğümler diğer düğümlere işaretçiler içermiyor. Sadece veri bloklarına (veya nesne küçükse veri alanı olarak ikiye katlanabilir).
vonbrand

4
Kopyalama sırasında izinlerin ve diğer verilerin korunduğundan emin olun, yani. kullanın cp -a(en azından GNU coreutils).
vonbrand

@ 0xC0000022L, dikkatlice bakarsanız, orijinal dosya için yalnızca geçici bir ad vardır, yalnızca son adımda yeni bir dosya oluşturulur.
vonbrand

@vonbrand Gerçekten de, hangi dosya sisteminin kullanıldığına bağlı olarak yapabilirler.
Johan

4

Bunu ~ / .bashrc dosyanızın sonuna koyun.

delink () { tmpfile="$1$(date)"; cp -a "$1" "$tmpfile"; mv "$tmpfile" "$1"; }

Bu şekilde çalıştırın

delink filename

3

Bir bash betiği ile yapmanın en iyi yolu şuna benzer:

if [ -f "$1" ] ; then
dir="$(dirname -- "$1")"
tmpfile="$(mktemp --tmpdir="$dir")"
cp --preserve=all -f -- "$1" "$tmpfile"
mv -f -- "$tmpfile" "$1"
fi

dikkat edilmesi gereken noktalar:

  • kopyalamaya çalışmadan önce dosyanın normal bir dosya olup olmadığını kontrol edin
  • kopya hazır olana kadar eski dosyayı yerinde tut
  • mktempvar olmadığı garanti edilen bir dosya oluşturmak için kullanın
  • kullanmak -füzerine yazma zorlamak ve --preserve=allorijinal dosyayı mümkün olduğunca benzer meta tutmak için
  • kullanımı --ve "yollar boşluk içeren ve / veya ile başlayan alıntı-

Mevcut (3.16) linux sistem çağrıları ile geçici bir dosya oluşturmadan değiştirme yapmak mümkün değildir: bir dosyanın üzerine atom olarak yazmak mümkündür (yani, eski dosyayı kaldırın ve tek bir işlem olarak yenisiyle değiştirin), dosya sisteminde adı olmayan bir dosyayla (yani işlev O_TMPFILEbayrağı kullanılarak oluşturulan geçici bir dosya) bunu yapmak mümkün değildir, opençünkü renameişlev girdi olarak bir dosya adı gerektirir (hiçbir sürümü renamegirdi olarak dosya tanımlayıcı olarak alınmaz - bakınız burada ) detaylar için


1
dirnameVe mktemparamalarınızdaki adı alıntılayamadığınızı unutmayın . Sizin için düzeltildi ...
derobert

@derobert oh teşekkür ederim, ama iç içe çift tırnak olduğu için bu işe yaramaz ... başka bir düzeltme gerekiyor! Kinda hate bash
pqnet

3
$( ... )-Style komutunun değiştirilmesi nedeniyle çalışacaktır . Bunun bir ` ... `tarzı daha güzel .
derobert

@derobert güzel, bilmiyordum. Ayrıca, `` satır içi kod etiketleri içinde '' nasıl kullanabilirsiniz?
pqnet

Ters eğik çizgilerle onlardan kaçabilirsiniz. `Sizi içeri sokmak için: `\``(tabii ki, size ne yazdığınızı göstermek için iki kez kaçtım).
derobert

-1

Aradığınız komut unlink


Belki de sorum açık değildi, ama "yerinde" ve örneklerle cpve mvsonradan dosyanın var olmasını diliyorum.
0xC0000022L

Ah, bunu net bulamadım, hayır. Öyleyse Johan'ın cevabına gitmelisin.
Jenny D

1
"Unlink" komutu sadece dosyayı kaldırır (unlink () sistem çağrısının yaptığı).
Raúl Salinas-Monteagudo

-1

Bu dosyaya sabit bağlantı olan tüm dosya adını arıyorsanız, şunları kullanabilirsiniz:

find -samefile myknowhardlinkfile

ayrıca ls -il myknowhardlinkfileaynı inode'a (üçüncü alan) sabit bağlı dosya adı sayısını gösterir.

101612442 -rw-rw-r--. 2 me me 0 Aug  5 07:07 myknowhardlinkfile

Yararlı olabilmesine rağmen, bu aslında soruyu cevaplamıyor.
Flimm
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.