Basit Linux komutu ile mutlak sembolik link göreceli sembolik linke dönüştürün


29

Ben yolun içine komple alt-sistemleri de var /home/user/systemdizinleri ile standart Linux yapısını içeren /bin, /home, /root, /usr, /var, /etc, ...

Bu alt dosya sistemi, göreceli veya mutlak sembolik bağlantılar içerir. Göreceli sembolik bağlantılar gayet iyi, onlar alt dosya sisteminde kalıyorlar /home/user/system. Ancak mutlak sembolik bağlantılar, alt dosya sisteminin dışındaki bir hedefi işaret ettiği için sorunludur.

Örnek olarak, aşağıdaki gibi mutlak bir sembolik bağlantı varsayıyoruz (alt dosya sisteminin içinde görülmektedir):

/usr/file1 -> /usr/lib/file1

Genel dosya sisteminde, şu anda bir bağlantımız var , alt dosya sisteminin içindeki bir dosya yerine, alt dosya sisteminin dışındaki /home/user/system/usr/file1bir dosyayı işaret ediyoruz ./usr/lib/file1/home/user/system/usr/lib/file1

Basit bir betiğe, tercihen her mutlak sembolik bağı göreceli olana çeviren tek bir komut satırı (rsync, chroot, find, ...) olmasını isterdim.

Verilen örnekte, bu göreceli bağlantı

/usr/file1 -> ../usr/lib/file1

4
Bu Q’yu çözmeye çalışmak isteyenler için, işte SO’nun denemesinden 250k´lık bir kullanıcı: stackoverflow.com/questions/2564634/… . Bu iş parçacığında birkaç potansiyel çözüm var, ancak her birinin ilgilendiği ve başkalarının ilgilenmediği özel durumları var.
slm

Yanıtlar:


20

İle symlinksfayda Mark Lord tarafından (birçok dağılımları tarafından sunulan; senin, ona sahip onu inşa etmezse kaynağı ):

chroot /home/user/system symlinks -cr .

Alternatif olarak, readlinkkomut ve -lnameyordama olan sistemlerde find(uyarı: denenmemiş kod):

cd /home/user/system &&
find . -lname '/*' -exec ksh -c '
  for link; do
    target=$(readlink "$link")
    link=${link#./}
    root=${link//+([!\/])/..}; root=${root#/}; root=${root%..}
    rm "$link"
    ln -s "$root${target#/}" "$link"
  done
' _ {} +

Bu güzel bir çözüm olurdu! Bununla birlikte, ifadenin _ {} +sonunda bulgunun anlamı nedir? Ayrıca, find: paths must precede expression: kshanlamlı görünmeyen bir hata alıyorum (yol , ksh ifadesini önceden aldığında ).
Alex,

@Alex _olan $0kabuk parçacığı için ve {} +olmak bağımsız değişkenler listesi ile ikame edilir $1, $2vb for link; do …ile (bu ayn var üzerinde döngüler for link in "$@"; do …). Hata findbir yazım hatası nedeniyle (Bir şekilde argüman etrafında tek tırnak yerine backquotes yazmayı başardım -lname).
Gilles 'SO- kötü olma' kas

Şimdi komut dosyası çalışır, ancak beklendiği gibi değil. Belki de yeterince hassas değildim, soruyu güncelledim.
Alex,

@Alex Sorun nedir? Bence prensip sağlam, fakat bazı kodlama hataları yapmış olabilirim. Denedin symlinksmi Bu senin problemini çözerdi - temelde bunun için tasarlandı ( sıkıntıya maruz kalman için can sıkıcıydı ( fakechroot hile yapmalı)).
Gilles 'SO- kötülük yapmayı kes'

1
Ek bir şey yüklemeye gerek kalmadan, kutunun dışında çalışan bir çözümü şiddetle görüyorum.
Alex,

4

Saf bash & coreutils, ../yol üzerinde gereksiz yere ihtiyaç duyulmadan sembolik bağları değiştirir :

find . -type l | while read l; do
    target="$(realpath "$l")"
    ln -fs "$(realpath --relative-to="$(dirname "$(realpath -s "$l")")" "$target")" "$l"
done

Değiştirebilirsin:

  • find .için find /path/to/directorybu dizinde sembolik dönüştürmek
  • ln -fsiçin echo ln -fskuru çalıştırmak için

Açıklama:

  • target="$(realpath "$l")" - sembolik bağlantı hedefine giden mutlak yolu bulur
  • ln -fs- varolan yeniden yazma symlink ( -s), zorlama ( -f) oluşturur
  • realpath -s "$l" - bağlantının kendisine giden mutlak yolu bulur
  • dirname "$(realpath -s "$l")" - sembolik bağlantıyı içeren dizine giden mutlak yolu bulur
  • realpath --relative-to="$(dirname "$(realpath -s "$l")")" "$target" - sembolik bağlantıya göre hedef yolunu bulur, başka bir deyişle: mutlak değeri bağıl yola dönüştürür

1
ifBozuk bağlantıları atlamak için bir cümle eklemenizi öneririm .
fuenfundachtzig

0

Bu bash snippet'i yapmalı. İlk form ne yapacağını yazdıracak; ikinci yapacak. Çıktıyı yıkıcı olduğu için dikkatlice incelerdim - ln -fmevcut bağlantının üzerine yazar.

TOP=/home/user/system
cd $TOP
find * -type l -print | while read l; do echo ln -sf $TOP$(readlink $l) $l; done
find * -type l -print | while read l; do      ln -sf $TOP$(readlink $l) $l; done

Bu, boşluk içeren isimler için başarısız olacağının yanı sıra, yanlış yol bu değil mi? Mutlak yolu ön ekler mi?
fuenfundachtzig

0

İşte saf bir sh çözümü.

cd / ev / kullanıcı / sistem ve
Bul -adı '/ *' |
okurken l; yap
  echo ln -sf $ (echo $ (echo $ l | sed 's | / [^ /] * | / .. | g') $ (okuma l $ $) | sed 's /...../' ) 1 l
bitti |
sh

0

Göreceli bağlantılarda mutlak dönüştürme, ssh ile uzak dizinleri bağlayan sshfs tarafından desteklenir.

Komut: orada

sudo sshfs <remote_user>@<remote_ip_address>:/ /home/<host_user>/mntpoint/ -o transform_symlinks -o allow_other

Komut, özellikle de <placeholders>, belirli bir ortama uyarlanacaktır.

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.