Oluşturulduktan sonra bir sembolik bağın işaret ettiği şeyi değiştirebilir misiniz?


122

Herhangi bir işletim sistemi, sembolik bir bağlantı (sembolik bağlantı) tarafından referans verilen yol adını değiştirmek için bir mekanizma (sistem çağrısı - komut satırı programı değil) - eskisinin bağlantısını kaldırıp yeni bir tane oluşturmanın dışında - sağlıyor mu?

POSIX standardı bunu yapmaz. Solaris 10 bunu yapmaz. MacOS X 10.5 (Leopard) bunu yapmaz. (Kesinlikle eminim ki ne AIX ne de HP-UX de yok. Bu Linux sistem çağrıları listesine bakılırsa , Linux da böyle bir sistem çağrısına sahip değil.)

İşe yarayan bir şey var mı?

(Cevabın "Hayır" olmasını bekliyorum.)


Olumsuzluğu kanıtlamak zor olduğu için soruyu yeniden düzenleyelim.

Halihazırda listelenmemiş bazı (Unix benzeri) işletim sistemlerinin bir sembolik bağın değerini yeniden yazmak için bir sistem çağrısı olmadığını biliyorsanız ( readlink() , eski sembolik bağlantıyı kaldırmadan ve yeni bir tane oluşturmadan bir sembolik ) , lütfen ekleyin - veya onları - bir cevapta.


Yeniden bağlanmanın nesi yanlış? Neden lneski bağlantının üzerine yazarak sadece komutu (veya API eşdeğerini) yayınlamıyorsunuz? Ne problemin var?
S.Lott

9
Komik - Bir programlama işi yapmak için bir sistem çağrısı olup olmadığını soruyorum ve soru 'başka siteye ait' olarak işaretleniyor.
Jonathan Leffler

3
Komik- Bir sistem çağrısı aradığınız kesinlikle net değildi ve bu ayrıntıyı eklemek için soruyu düzenlediniz. Öyleyse, siz daha yazmadan önce insanların bir şeyi kesintiye uğratmasını nasıl bekleyebilirsiniz?
Pascal Thivent

2
@ S.Lott: Güvenlik ve sembolik bağlantılar üzerine bir makale yazıyorum. Bir noktada "gerçek sahip, grup, sembolik bağın kendisindeki izinler önemsizdir" iddiasını yapıyorum ve bunun nedeni, sembolik bağın sahibinin yalnızca onu kaldırıp değeri değiştirememesidir. 'Sembolik bağ değerini yeniden yazma' etkisini elde etmenin sembolik bağını kaldırmanın dışında bir yol olmadığını iki kez kontrol ediyorum. Ham diske doğrudan erişimi görmezden geliyorum ve FS'yi bu şekilde hackliyorum - bu kök ayrıcalığı gerektiriyor ve endişelerim root olmayan kullanıcılarla ilgili, kökün ne yapabileceğiyle değil.
Jonathan Leffler

4
@Pascal: Özür dilerim - insanlar niyet ettiğimden bir tanjantla gidene kadar sistem çağrıları hakkında konuştuğumun net olmadığını fark etmemiştim (ki bu söylediğimden açıkça farklıydı). Yanlış yönlendirdiğim için üzgünüm; kasıtsızdı.
Jonathan Leffler

Yanıtlar:


106

AFAIK, hayır, yapamazsınız. Onu kaldırmalı ve yeniden yaratmalısınız. Aslında, bir sembolik bağın üzerine yazabilir ve böylece referans gösterilen yol adını güncelleyebilirsiniz:

$ ln -s .bashrc test
$ ls -al test
lrwxrwxrwx 1 pascal pascal 7 2009-09-23 17:12 test -> .bashrc
$ ln -s .profile test
ln: creating symbolic link `test': File exists
$ ln -s -f .profile test
$ ls -al test
lrwxrwxrwx 1 pascal pascal 8 2009-09-23 17:12 test -> .profile

DÜZENLEME : OP'nin bir yorumda belirttiği gibi, --forceseçeneğin kullanılması lndaha unlink()önce bir sistem çağrısı yapılmasını sağlayacaktır symlink(). Aşağıda, stracelinux kutumdaki çıktı bunu kanıtlıyor:

$ strace -o /tmp/output.txt ln -s -f .bash_aliases test
$ grep -C3 ^unlink /tmp/output.txt 
lstat64("test", {st_mode=S_IFLNK|0777, st_size=7, ...}) = 0
stat64(".bash_aliases", {st_mode=S_IFREG|0644, st_size=2043, ...}) = 0
symlink(".bash_aliases", "test")        = -1 EEXIST (File exists)
unlink("test")                          = 0
symlink(".bash_aliases", "test")        = 0
close(0)                                = 0
close(1)                                = 0

Sanırım son cevap "hayır".

DÜZENLEME : Aşağıdakiler, Arto Bendiken'in yaklaşık 2016 yılında unix.stackexchange.com adresindeki yanıtından kopyalanmıştır .

Bu olabilir gerçekten atomik olarak yapılabilir rename(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:

Yeni yol sembolik bir bağlantıya atıfta bulunursa , bağlantının üzerine yazılır.

Kabukta bunu şu şekilde yaparsınız mv -T:

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

Sen olabilir straceo son komut emin olmak için gerçekten kullanıyorrename(2) kaputun altında:

$ 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 şunu kullanın mv -h dönüşümlü olarak .

Editörün notu: Capistrano bunu ~ 2.15'ten beri yıllardır böyle yapıyor. Bu çekme talebine bakın .


2
'-F' seçeneği, 'ln'yi unlink () sonra symlink () sistem çağrılarını yapmaya zorlamaz mı?
Jonathan Leffler

1
Olur. Ama soru "bunu bir adımda nasıl yaparım" olarak algılanabilir ve sonra "adım" tanımına (komut satırı) indirgenebilir. syscall?
Michael Krelin - hacker

1
Sorunuza sistem çağrısı ifadeleri eklediğinizi fark ettim ;-)
Michael Krelin - hacker

2
@Pascal: öyle. Solaris'te, 'truss ln -spx' ve 'truss ln -s -fpx'den gelen çıktı, ikinci durumda symlink () çağrısından önce bir unlink () çağrısı gösterir (ve birinci durumda başarısız bir symlink () çağrısı). Bunun Unix'in tüm varyantları olmasa da çoğu için geçerli olmasını beklerdim.
Jonathan Leffler

12
@ Taai açıklamasına +1 - bir dizine başvuran (işaret eden) bir sembolik bağlantıyla ilgileniyorsanız, bu numaranın çalıştığından emin olmak için "-n" belirtmeniz gerekir.
wally

161

Evet yapabilirsin!

$ ln -sfn source_file_or_directory_name softlink_name

9
Cevap verdiğiniz için teşekkürler. -fOpsiyon aracı yeni bir tane oluşturmadan önce 'Mevcut hedefi kaldırmak'. Yani, bu komut sonuca ulaşır, ancak bunu yaparak unlink(2)takip eder symlink(2). Asıl soru bununla ilgili değildi. Ayrıca, kabul edilen cevabın ve bir sonraki en çok oylanan cevabın her ikisinin ln -sfde işi yapmak için kullanıldığını , ancak straceçıktının gösterdiği gibi bunu yaptığını unlink()ve symlink()bir sembolik bağlantıyı değiştirmek için bir sistem çağrısı olmadığını unutmayın.
Jonathan Leffler

17
Orijinal bağlantı bir dosya yerine bir dizine gittiğinde -n gerekli görünüyor.
steampowered

11
'N' anahtarı önemlidir. Sembolik bağlantının güncellenmemesi, ancak komutun 'eskrim yok' seçeneği ayarlanmadığı için mevcut bağlantı içinde başka bir bağlantı oluşturması sorunuyla uğraştım.
Jonathan Gruber

14

Eski sembolik bağın açıkça ayrılması gerekli değildir. Bunu yapabilirsiniz:

ln -s newtarget temp
mv temp mylink

(veya eşdeğer sembolik bağlantıyı kullanın ve çağrıları yeniden adlandırın). Bu, açıkça bağlantıyı kaldırmaktan daha iyidir çünkü yeniden adlandırma atomiktir, bu nedenle bağlantının her zaman eski veya yeni hedefi göstereceğinden emin olabilirsiniz. Ancak bu, orijinal inode'u yeniden kullanmayacaktır.

Bazı dosya sistemlerinde, sembolik bağın hedefi, yeterince kısaysa, inode'un kendisinde (blok listesi yerine) saklanır; bu, oluşturulduğu anda belirlenir.

Gerçek sahip ve grubun önemsiz olduğu iddiasıyla ilgili olarak, Linux'ta symlink (7) önemli olduğu bir durum olduğunu söylüyor:

Mevcut bir sembolik bağın sahibi ve grubu lchown (2) kullanılarak değiştirilebilir. Bir sembolik bağın sahipliğinin önemli olduğu tek zaman, bağın yapışkan bit kümesine sahip bir dizinde kaldırılması veya yeniden adlandırılmasıdır (bkz. Stat (2)).

Bir sembolik bağlantının son erişim ve son değişiklik zaman damgaları, utimensat (2) veya lutimes (3) kullanılarak değiştirilebilir.

Linux'ta, herhangi bir işlemde sembolik bir bağlantının izinleri kullanılmaz; izinler her zaman 0777'dir (tüm kullanıcı kategorileri için okuma, yazma ve çalıştırma) ve değiştirilemez.


@ mark4o: The Good - Sticky-it dizinindeki lchown () ve sahiplik referansı yararlıdır - teşekkürler. Lchown () 'ın farkındaydım ve tezim için önemli değildi. Ayrıca yapışkan bit dizinlerin farkındaydım; Bence sahiplik, kuralların neredeyse standart bir sonucu - fark ve muhtemelen neden çağrılmasının nedeni, normalde bir dosyayı yazabiliyorsanız kaldırabilmeniz ve sözde herkesin bir sembolik bağa yazabilmesidir çünkü 777 izinleri, ancak bu durumda kurallar biraz farklıdır.
Jonathan Leffler

1
@ mark4o: Çok İyi Değil - gösterilen komut dizisi düşündüğünüz şeyi yapmıyor (en azından senaryoda:) set -x -e; mkdir junk; ( cd junk; mkdir olddir newdir; ln -s olddir mylink; ls -ilR; ln -s newdir temp; ls -ilR; mv temp mylink; ls -ilR; ); rm -fr junk. Dizinler yerine oldfile ve newfile dosyaları oluşturur ve eşdeğer komut dosyasını çalıştırırsanız (esas olarak olddir'i eski dosyaya, newdir'i yeni dosyaya çevirirseniz), beklediğiniz etkiyi elde edersiniz. Sadece bir ekstra karmaşıklık! Cevap için teşekkürler.
Jonathan Leffler

2

Sadece yukarıdaki doğru cevaplara bir uyarı:

-F / --force Yöntemini kullanmak, kaynağı ve hedefi karıştırırsanız dosyayı kaybetme riski sağlar:

mbucher@server2:~/test$ ls -la
total 11448
drwxr-xr-x  2 mbucher www-data    4096 May 25 15:27 .
drwxr-xr-x 18 mbucher www-data    4096 May 25 15:13 ..
-rw-r--r--  1 mbucher www-data 4109466 May 25 15:26 data.tar.gz
-rw-r--r--  1 mbucher www-data 7582480 May 25 15:27 otherdata.tar.gz
lrwxrwxrwx  1 mbucher www-data      11 May 25 15:26 thesymlink -> data.tar.gz
mbucher@server2:~/test$ 
mbucher@server2:~/test$ ln -s -f thesymlink otherdata.tar.gz 
mbucher@server2:~/test$ 
mbucher@server2:~/test$ ls -la
total 4028
drwxr-xr-x  2 mbucher www-data    4096 May 25 15:28 .
drwxr-xr-x 18 mbucher www-data    4096 May 25 15:13 ..
-rw-r--r--  1 mbucher www-data 4109466 May 25 15:26 data.tar.gz
lrwxrwxrwx  1 mbucher www-data      10 May 25 15:28 otherdata.tar.gz -> thesymlink
lrwxrwxrwx  1 mbucher www-data      11 May 25 15:26 thesymlink -> data.tar.gz

Elbette bu amaçlanmıştır, ancak genellikle hatalar meydana gelir. Bu nedenle, sembolik bağın silinmesi ve yeniden oluşturulması biraz daha fazla iş ama aynı zamanda biraz tasarruf sağlar:

mbucher@server2:~/test$ rm thesymlink && ln -s thesymlink otherdata.tar.gz 
ln: creating symbolic link `otherdata.tar.gz': File exists

en azından dosyamı saklıyor.


A -fveya --forceseçeneğini kullanmak her zaman biraz tehlikelidir; kullanıcının ne hakkında olduğunu bildiğini varsayar. Alışkanlıkla kullanırsanız iki kat ölümcüldür ( rm -fr …her seferinde tehlikelidir).
Jonathan Leffler

1

Bağlantısını koparmak ve yenisini oluşturmak sonunda aynı şeyi yapmaz mı?


2
Neden ilk etapta bağlantıyı keselim? Neden basitçe üzerine yazmıyorsunuz?
S.Lott

5
Net sonuç yaklaşık olarak aynıdır - ancak genel olarak sahip ve grup ve son değiştirilen zamanlar (ve muhtemelen inode numarası) hepsi farklı olacaktır.
Jonathan Leffler

2
@ S.Lott: Hangi sistem çağrısı 'üzerine yazıyor'? POSIX'te böyle bir çağrı yoktur. Solaris ve MacOS X'te böyle bir çağrı yoktur. Bunu yapmak için bir çağrı var mı ... Linux, AIX, HP-UX, Unix'e benzeyen başka herhangi bir şey? Windows gerçekten aynı şekilde sembolik bağlara sahip değil, AFAICT, bu yüzden analizim için kritik değil - ancak eşdeğer Windows API ile ilgili bilgiler faydalı olacaktır.
Jonathan Leffler

@Jonathan Leffler: Ummm .... ln --forcekomut kesinlikle mevcut bir bağlantının üzerine yazacak .
S.Lott

Beyler, bence farklı amaçlarla konuşuyorsunuz. S.Lott bir yürütülebilir dosyayı tartışırken ln (1), mat b. gerçeği tartışıyor symlink (2)mu değil üzerine yazma destekler. İkiniz de haklısınız ve uygulamasına ln (1)bakmanın, bağlantıyı kaldırma prosedürünü gerçekleştirmenin en idomatik yolunu vereceğini öneririm.
dmckee --- eski moderatör kedi

0

İşe yaraması durumunda: midnight Commander (mc) ile bir sembolik bağlantıyı düzenlemenin bir yolu var. Menü komutu (mc arayüzümde Fransızca):

Fichier / Éditer le lien symbolique

hangisine çevrilebilir:

File / Edit symbolic link

Kısayol Cx Cs'dir

Belki dahili olarak ln --forcekomutu kullanıyor, bilmiyorum.

Şimdi, bir çok sembolik bağı aynı anda düzenlemenin bir yolunu bulmaya çalışıyorum (buraya böyle geldim).


1
MC'nin perde arkasında ne yaptığını doğruladınız mı? Aslında Unix benzeri sistemlerin sağladığı unlink()için symlink(), aslında bunu a ile takip etmesi olasılığını koyardım.
Jonathan Leffler

Hayır, kontrol etmedim. Ve evet, aslında söylediğiniz gibi yapması oldukça muhtemeldir.Bir metin kutusunu düzenlemem gerçeği, sembolik bağlantı hedefini gerçekten düzenlediğim hissini veriyor, ama muhtemelen kandırıldım ...
Pierre

0

Teknik olarak, mevcut bir sembolik bağı düzenlemek için yerleşik bir komut yoktur. Birkaç kısa komutla kolayca elde edilebilir.

Var olan bir sembolik bağlantıyı güncellemek için yazdığım küçük bir bash / zsh işlevi :

# -----------------------------------------
# Edit an existing symbolic link
#
# @1 = Name of symbolic link to edit
# @2 = Full destination path to update existing symlink with 
# -----------------------------------------
function edit-symlink () {
    if [ -z "$1" ]; then
        echo "Name of symbolic link you would like to edit:"
        read LINK
    else
        LINK="$1"
    fi
    LINKTMP="$LINK-tmp"
    if [ -z "$2" ]; then
        echo "Full destination path to update existing symlink with:"
        read DEST
    else
        DEST="$2"
    fi
    ln -s $DEST $LINKTMP
    rm $LINK
    mv $LINKTMP $LINK
    printf "Updated $LINK to point to new destination -> $DEST"
}

2
Çaba için teşekkür ederim. Bu, C dili sistem çağrısı olma ihtiyacımı karşılamıyor. Bağlantıyı tutan dizine yazma izniniz olduğu sürece bir bağlantıyı değiştirmenin birçok yolu vardır (bunu gerektirir). Şimdi bile, bir sembolik bağın değerini yapmadan unlink()ve symlink()yeni değerle değiştirmenin hiçbir yolu yok , ki bu kodunuzla perde arkasında olan şeydir. Şahsen, işlevin tam olarak iki (veya belki ikisinin bir katı) argüman üzerinde ısrar etmesini ve çağrı doğru değilse kefaletini isterim. Yine de bu belirli bir bakış açısı.
Jonathan Leffler
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.