Kişi bir sembolik bağlantıyı meşgul kutusundaki bir dizine atomik olarak nasıl değiştirir?


18

(Mümkün olduğunca yakın) atomik bir symlink değiştirmeye çalışıyorum. Denedim:

ln -sf other_dir existing_symlink

Bu, yeni symlink'i varolan_symlink'in işaret ettiği dizine koydu.

ln -sf other_dir new_symlink
mv -f new_symlink existing_symlink

Aynı şeyi yaptı: Symlink'i dizine taşıdı.

cp -s other_dir existing_symlink

Reddediyor çünkü bu bir dizin.

Bunun mv -Tiçin yapılmış olduğunu okudum , ancak busybox -Tbayrağı yok.

Yanıtlar:


1

Atomik operasyonu nasıl alabileceğinizi anlamıyorum. Adlı man sayfası symlink(2),EEXIST , hedefin zaten mevcut olup . Çekirdek atomik işlemi desteklemiyorsa, kullanıcı alanı sınırlamalarınız önemsizdir.

Ayrıca sahip mv -Tolsanız bile nasıl yardımcı olduğunu görmüyorum . GNU mv ile düzenli bir Linux kutusunda deneyin:

$ mkdir a b
$ ln -s a z
$ mv -T b z
mv: cannot overwrite non-directory `z' with directory `b'

Sanırım bunu iki adımda yapmanız gerekecek: eski sembolik bağlantısını kaldırın ve yeniden oluşturun.


1
Gerçekten de, ne yazık ki bir sembolik atomik olarak değiştirmenin hiçbir yolu yoktur. Yapabileceğiniz en iyi şey eski bağlantıyı kaldırmak ve yeni bir bağlantı oluşturmaktır. GNU coreutils, bunu tek bir komutla ( ln -snf) yapma seçeneğine sahiptir , ancak yine de kaputun altında iki sistem çağrısı vardır.
Gilles 'SO- kötü olmayı bırak'

43

Bu olabilir gerçekten ile atomik yapılabilirrename(2) ilk geçici adı altında yeni sembolik oluşturarak ve ardından temiz bir şekilde tek seferde eski sembolik üzerine yazarak. Gibi adam sayfası devletler:

Eğer yol sembolik bir bağlantıya işaret bağlantının üzerine yazılır.

Kabukta, bunu mv -T aşağıdaki gibi :

$ mkdir a b
$ ln -s a z
$ ln -s b z.new
$ mv -T z.new z

Yapabilirsin strace son komutu gerçekten rename(2)de kaputun altında kullandığından emin olmak için yapabilirsiniz :

$ strace mv -T z.new z
lstat64("z.new", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
lstat64("z", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
rename("z.new", "z")                    = 0

Yukarıda, her ikisinin de mv -T ve straceLinux özgüdür.

FreeBSD'de mv -hdönüşümlü olarak kullanın .


1
Çok hoş! Sonunda z'den b'ye bir bağlantınız olduğunu söylemek yardımcı olabilir!
Vincenzo Pii

İşletim sisteminden bağımsız bir çözüm için, renamesistem çağrısını mv -hveya yerine doğrudan kullanabilen bir komut dosyası dili kullanın mv -T. Örneğin Perl ile:perl -e 'rename "z.new", "z" or die $!'
Slaven Rezic

8

Arto'nun burada kaldığı yerden devam mv -Tederseniz , bu tamamen mümkündür, hatta olmadan , sadece hedef dizinle aynı ada sahip yeni bir symlink oluşturmanız ve hedefinizin mvüst dizinine eklemeniz gerekir:

mkdir -p tmp/real_dir1 tmp/real_dir2
touch tmp/real_dir1/a tmp/real_dir2/a
# start with ./target_dir pointing to tmp/real_dir1
ln -s tmp/real_dir1 target_dir
# create a symlink named target_dir in tmp, pointing to real_dir2
ln -sf tmp/real_dir2 tmp/target_dir
# atomically mv it into ./ replacing ./target_dir
mv tmp/target_dir ./

( Http://axialcorps.wordpress.com/2013/07/03/atomically-replacing-files-and-directories/ ) aracılığıyla alınan kod örneği


3

Denedin ln -snfmi

-nHedef, bir dizine sembolik bir bağlantı olduğunda seçenek , altına yazmak yerine hedefin üzerine yazar.

Şerefe


3
ln -snfatomik değildir: hedefin bağlantısını kaldırır, ardından istenen sembol bağlantısını oluşturur.
Gilles 'SO- kötü olmayı bırak

2
OP'nin bir sembolik bağın atomik olarak değiştirilmesine "mümkün [e] kadar" yaklaşmakla ilgilendiği düşünüldüğünde, bu oldukça makul bir cevaptır. Atomik yaklaşabilecek (veya olabilen) daha iyi bir tane varsa, o kabul edilebilir. Ben aşağı inmek için bir ihtiyaç olduğunu sanmıyorum.
Wilco
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.