Znajdź tylko miejsce docelowe dowiązania symbolicznego

50

Do użycia w skrypcie powłoki szukam sposobu wiersza polecenia, aby uzyskać miejsce docelowe dowiązania symbolicznego. Najbliższe, do jakiego do tej pory doszedłem, to stat -N srcjakie wyniki src -> dst. Oczywiście mógłbym przeanalizować dane wyjściowe i uzyskać dst, ale zastanawiam się, czy istnieje jakiś bezpośredni sposób na uzyskanie celu.

gerrit
źródło

Odpowiedzi:

61

Inną opcją byłoby użycie specjalnie zaprojektowanego polecenia, readlinkjeśli jest dostępne.

Na przykład

$ readlink -f `command -v php`
/usr/bin/php7.1
nikitautiu
źródło
21
Użyj, readlink -fjeśli chcesz znać ostatni cel dowiązania symbolicznego, a nie tylko następny .
scai
Słuszna uwaga! Zapomniałem o tym.
nikitautiu
11
Zauważ, że -fjest to nieprzenośne rozszerzenie GNU readlink.
bahamat
2
Kiedy readlink nie będzie dostępny? Dzięki.
tommy.carstensen
2
@ tommy.carstensen readlink (1) został dodany do GNU coreutils w 2003 roku, więc w dzisiejszych czasach możesz prawdopodobnie polegać na nim praktycznie na wszystkich systemach korzystających z coreutils. (Por. Git.savannah.gnu.org/cgit/coreutils.git/commit/src/… )
Josip Rodin
16

W systemie Mac OS X i FreeBSD / NetBSD / itp. jego:

stat -f %Y <filename>

Bardziej ogólnie wydaje mi się, że rozwiązaniem jest (stat --printf =% N używa dziwnych cudzysłowów):

ls -l b | sed -e 's/.* -> //'

Przykład:

# ln -s a b
# stat -f %Y b
a

Inną metodą jest:

# find b -maxdepth 0 -printf %l
a#

Ostatnia linia jest zniekształcona, ponieważ nie ma nowej linii, ale to dobrze, jeśli potrzebujesz wyniku w zmiennej, takiej jak

# f=$(find b -maxdepth 0 -printf %l)
# echo $f
a

Jest -maxdepthto konieczne, aby zapobiec findzstępowaniu do katalogów, jeśli bjest to katalog.

Coroos
źródło
Całkowicie przejrzałem, stat --printf='%N\n'jest dokładnie tym, czego chcę, dziwne cytaty mi nie przeszkadzają, ich te same cytaty rm i ln
interaktywne
Najwyraźniej nie jest to przenośne, ponieważ w Linuksie statystyka GNU coreutils (1) ma inne parametry i wypisuje link -> destna wyjściu. The (1) rozwiązanie znajdź powinny być sprawdzane, czy to z findutils GNU albo inaczej ...
Josip Rodin
Proszę nie zapomnieć o cytowaniu zmiennych, z echo $fpewnością nie daje to, czego oczekujesz, gdy dowiązanie symboliczne wskazuje /*(tak, jest to możliwe)
Camusensei
3

Można to zrobić za pomocą GNU find: find src -prune -printf "%l\n".

gerrit
źródło
1

Przenośne: bez powodzenia, z wyjątkiem użycia heurystyki do analizy danych wyjściowych ls -l lub użycia perl -le 'print readlink("some-file")'

niektóre systemy mają readlinkpolecenie, niektóre z -fopcją uzyskania bezwzględnej ścieżki.

Istnieją różne implementacje statpolecenia jako opakowania dla wywołań systemowych stat/ lstat. GNU jeden nie jest pod tym względem użyteczny, ale wbudowany w Zsh jest bardziej:

zmodload zsh/stat
stat +link the-link

Nadal dzięki Zsh możesz uzyskać bezwzględną ścieżkę do pliku (usuwa każdy komponent dowiązania symbolicznego) za pomocą :Amodyfikatora (dotyczy rozwijania zmiennych, rozszerzania historii i globowania:

~$ gstat -c %N b
`b' -> `a'
~$ var=b
~$ echo $var:A
/home/me/a
~$ echo b(:A)
/home/me/a
~$ echo ?(@:A)
/home/me/a
Stéphane Chazelas
źródło
1

W systemie, w którym nie mam poleceń readlinklub statpoleceń, ale mam Python 2.x, używam krótkiego skryptu:

#!/usr/bin/env python

import os, sys

if __name__ == "__main__":
    src = sys.argv[1]
    target = os.readlink(src)
    if not os.path.isabs(target):
            target = os.path.abspath(os.path.join(os.path.dirname(src), target))
    print target

Zauważ, że w przeciwieństwie do readlink -ftego może występować tylko jeden poziom dowiązania symbolicznego.

Rakslice
źródło
1

Przenośna ścieżka real Bash

bash_realpath() {
  # print the resolved path
  # @params
  # 1: the path to resolve
  # @return
  # &1: the resolved link path

  local path="${1}"
  while [[ -L ${path} && "$(ls -l "${path}")" =~ -\>\ (.*) ]]
  do
    path="${BASH_REMATCH[1]}"
  done
  echo "${path}"
}
Léa Gris
źródło
0

realpathpolecenie coreutilspakietu,

zgodnie z linkiem readlinkna stronie podręcznika polecenia.


na przykład:

realpath /bin/python

wyjścia

/usr/bin/python2.7

na mojej maszynie.


źródło