Konwertuj bezwzględne dowiązanie symboliczne na względne dowiązanie symboliczne za pomocą prostej komendy Linux

29

Mam pełną sub-plików wewnątrz ścieżki /home/user/systemzawierającej standardową strukturę Linux z katalogów /bin, /home, /root, /usr, /var, /etc, ...

Ten podsystem plików zawiera dowiązania symboliczne, względne lub bezwzględne. Względne dowiązania symboliczne są w porządku, pozostają w pod-systemie plików /home/user/system. Ale bezwzględne dowiązania symboliczne są problematyczne, ponieważ wskazują na cel poza podsystemem plików.

Jako przykład przyjmujemy bezwzględne dowiązanie symboliczne w następujący sposób (widoczne w pod-systemie plików):

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

W ogólnym systemie plików mamy link, /home/user/system/usr/file1który teraz wskazuje na plik /usr/lib/file1poza podsystemem, zamiast na plik /home/user/system/usr/lib/file1 wewnątrz podsystemu.

Chciałbym mieć prosty skrypt, najlepiej pojedynczy wiersz poleceń (rsync, chroot, find, ...), który konwertuje każde absolutne dowiązanie symboliczne na względne.

W podanym przykładzie ten względny link stałby się

/usr/file1 -> ../usr/lib/file1
Alex
źródło
4
Dla zainteresowanych przystąpieniem do rozwiązania tego Q, oto użytkownik 250k rep'd z tak jest próba: stackoverflow.com/questions/2564634/... . Istnieje kilka potencjalnych rozwiązań w tym wątku, ale każdy z nich ma określone sytuacje, z którymi ma do czynienia, i inne, których nie ma.
slm

Odpowiedzi:

20

Dzięki symlinksnarzędziu Mark Lord (oferowanemu przez wiele dystrybucji; jeśli twój go nie ma, zbuduj go ze źródła ):

chroot /home/user/system symlinks -cr .

Alternatywnie, w systemach, które mają readlinkpolecenie i -lnamepredykat find(ostrzeżenie: nieprzetestowany 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
' _ {} +
Gilles „SO- przestań być zły”
źródło
To byłoby miłe rozwiązanie! Co jednak oznacza to wyrażenie _ {} +na końcu znaleziska? Ponadto find: paths must precede expression: kshpojawia się błąd, który wydaje się nie mieć sensu (ponieważ ścieżka poprzedza wyrażenie ksh).
Alex
@Alex _jest $0na fragmencie powłoki i {} +otrzymuje listę argumentów, które stają się $1, $2itp, które for link; do …obwodów nad (jest synonimem for link in "$@"; do …). Błąd z findwynika z literówki (jakoś udało mi się wpisać cudzysłowy zamiast pojedynczych cudzysłowów wokół argumentu do -lname).
Gilles „SO- przestań być zły”
Teraz skrypt działa, ale nie działa zgodnie z oczekiwaniami. Może nie byłem wystarczająco precyzyjny, zaktualizowałem pytanie.
Alex
@Alex Jaki jest problem? Myślę, że zasada jest dobra, ale mogłem popełnić pewne błędy w kodowaniu. Próbowałeś symlinks? Rozwiązałoby to twój problem - po prostu do tego został zaprojektowany (z irytacją, że musisz go uruchomić chrootowany ( fakechroot powinien załatwić sprawę )).
Gilles „SO- przestań być zły”
1
Zdecydowanie spoglądam na rozwiązanie działające od razu, bez potrzeby instalowania czegoś dodatkowego.
Alex
4

Czysty bash i coreutils, zmienia dowiązania symboliczne na względne bez zbędnych ../s na ścieżce:

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

Możesz się zmienić:

  • find . do find /path/to/directory konwersji dowiązań symbolicznych w tym katalogu
  • ln -fsaby echo ln -fsna sucho

Wyjaśnienie:

  • target="$(realpath "$l")" - znajduje bezwzględną ścieżkę do celu dowiązania symbolicznego
  • ln -fs- tworzy symlink ( -s), wymuszając ( -f) przepisanie istniejącego
  • realpath -s "$l" - znajduje absolutną ścieżkę do samego dowiązania symbolicznego
  • dirname "$(realpath -s "$l")" - znajduje bezwzględną ścieżkę do katalogu zawierającego dowiązanie symboliczne
  • realpath --relative-to="$(dirname "$(realpath -s "$l")")" "$target" - znajduje ścieżkę celu względem dowiązania symbolicznego, innymi słowy: konwertuje ścieżkę bezwzględną na ścieżkę względną
LUMIFAZA
źródło
1
Sugeruję dodanie ifklauzuli, aby pominąć niedziałające linki.
fuenfundachtzig
0

Ten fragment bash powinien to zrobić. Pierwszy formularz wypisze, co by zrobił; drugi to zrobi. Dokładnie sprawdziłbym wynik, ponieważ jest on destrukcyjny - ln -fzastępuje istniejący link.

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
qneill
źródło
Poza tym, że nie powiedzie się to w przypadku nazw ze spacjami, czy nie jest to odwrotna sytuacja? Prefiks ścieżki bezwzględnej?
fuenfundachtzig
0

Oto czyste rozwiązanie sh.

cd / home / user / system &&
odnaleźć . -lname „/ *” |
podczas gdy czytam l; robić
  echo ln -sf $ (echo $ (echo $ l | sed 's | / [^ /] * | / .. | g') $ (readlink $ l) | sed 's /.....//' ) $ l
zrobione |
sh
Diomidis Spinellis
źródło
0

Przekształcanie wartości bezwzględnej w odnośnikach względnych jest obsługiwane przez sshfs, który montuje zdalne katalogi przez ssh.

Polecenie brzmi: tam

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

Polecenie, zwłaszcza <placeholders>, powinno być dostosowane do konkretnego środowiska.

użytkownik260694
źródło