Примечание: namei
(см Anthony Geoghegan's answer) и chase
(см Toby Speight's answer) большие Linux варианты; этот ответ предлагает:
* кросс-платформенный решения
* печать из абсолютных путей для каждый шаг цепи, даже если алиасы определяются с относительными путями.
- Рассмотрим
typex
utility (написанный мной), который печатает символическую ссылку цепь данной утилиты в $PATH
, используя абсолютные путей в каждом шаге (typex
также обеспечивает дополнительную информацию, аналогичную, но более обширный, чем type
).
- Простейшая установка, с узлом.JS установлены:
npm install typex -g
- Пример (обратите внимание, как информация о версии, полученные с
--version
, прилагается - не будет работать на java
, однако, который использует -version
):
$ typex awk
BINARY: /usr/bin/[email protected] -> /etc/alternatives/[email protected] -> /usr/bin/gawk [GNU Awk 4.0.1]
rreadlink
- это утилита нижнего уровня (написанная мной), которая печатает цепочку символических ссылок как абсолютные пути для любого заданного пути к файловой системе.
Ниже rreadlinkchain()
, A полностью POSIX-совместимый скрипт/функция - она использует только POSIX shell language features и только вызовы утилиты, совместимые с POSIX. Это совместимый с POSIX вариант функции bash
, лежащий в основе двух утилит выше, и был с благодарностью адаптирован от this answer; применены к примеру: rreadlinkchain "$(which java)"
ноты Совместимость:
typex
и rreadlink
, при установке из реестра НПМ, поддерживают как OS X и Linux, но они , вероятно, также работают на системах BSD с bash
, при установке вручную.
Как указано, rreadlinkchain()
функция ниже полностью совместима с POSIX и должна работать на большинстве Unix-подобных платформ.
#!/bin/sh
## -------
# SYNOPSIS
# rreadlinkchain <symLink>
# DESCRIPTION
# Recursive readlink: prints the CHAIN OF SYMLINKS from the input
# file to its ultimate target, as ABSOLUTE paths, with each path on a separate
# line.
# Only the ultimate target's path is canonical, though.
# A broken symlink in the chain causes an error that reports the
# non-existent target.
# An input path that is not a symlink will print its own canonical path.
# LIMITATIONS
# - Won't work with filenames with embedded newlines or filenames containing
# the string ' -> '.
# COMPATIBILITY
# Fully POSIX-compliant.
# EXAMPLES
# # Print the symlink chain of the `git` executable in the $PATH.
# rreadlinkchain "$(which git)"
# # Ditto, using single-line `ls -l`-style format ('[email protected] -> b')
# rreadlinkchain "$(which git)" | sed -nE -e '$!{a\'$'\n''@ -> ' -e '}; p' | tr -d '\n'
# THANKS
# https://stackoverflow.com/a/1116890/45375
rreadlinkchain() (# execute in *subshell* to localize the effect of `cd`, ...
target=$1 targetDir= targetName= CDPATH=
# Try to make the execution environment as predictable as possible:
# All commands below are invoked via `command`, so we must make sure that
# `command` itself is not redefined as an alias or shell function.
# (Note that command is too inconsistent across shells, so we don't use it.)
# `command` is a *builtin* in bash, dash, ksh, zsh, and some platforms do not
# even have an external utility version of it (e.g, Ubuntu).
# `command` bypasses aliases and shell functions and also finds builtins
# in bash, dash, and ksh. In zsh, option POSIX_BUILTINS must be turned on for
# that to happen.
{ \unalias command; \unset -f command; } >/dev/null 2>&1
[ -n "$ZSH_VERSION" ] && options[POSIX_BUILTINS]=on # make zsh find *builtins* with `command` too.
while :; do
# Unless the file is a symlink OR exists, we report an error - note that using `-e` with a symlink reports the *target*'s existence, not the symlink's.
[ -L "$target" ] || [ -e "$target" ] || { command printf '%s\n' "ERROR: '$target' does not exist." 1>&2; return 1; }
# !! We use `cd` to change to the target's folder
# !! so we can correctly resolve the full dir. path.
command cd "$(command dirname -- "$target")" # note: cd "" is the same as cd . - i.e., a no-op.
targetDir=$PWD
targetName=$(command basename -- "$target")
[ "$targetName" = '/' ] && targetName='' # !! curiously, `basename /` returns '/'
done=0
if [ ! -L "$targetName" ]; then
# We've found the ultimate target (or the input file wasn't a symlink to begin with).
# For the *ultimate* target we want use `pwd -P` to make sure we use the actual, physical directory,
# (not a symlink) to get the *canonical* path.
targetDir=$(command pwd -P)
done=1
fi
# Print (next) path - note that we manually resolve paths ending
# in /. and /.. to make sure we have a normalized path.
if [ "$targetName" = '.' ]; then
command printf '%s\n' "${targetDir%/}"
elif [ "$targetName" = '..' ]; then
# Caveat: something like /var/.. will resolve to /private (assuming
# /[email protected] -> /private/var), i.e. the '..' is applied AFTER canonicalization.
command printf '%s\n' "$(command dirname -- "${targetDir}")"
else
command printf '%s\n' "${targetDir%/}/$targetName"
fi
# Exit, if we've hit the non-symlink at the end of the chain.
[ "$done" = 1 ] && break
# File is symlink -> continue to resolve.
# Parse `ls -l` output, which, unfortunately, is the only POSIX-compliant
# way to determine a symlink's target. Hypothetically, this can break with
# filenames containig literal ' -> ' and embedded newlines.
target=$(command ls -l -- "$targetName")
target=${target#* -> }
done
)
rreadlinkchain "[email protected]"
Возможный дубликат [Как разрешить символические ссылки в сценарии оболочки] (http://stackoverflow.com/questions/7665/how-to-resolve-symbolic-links-in-a-shell-script) –
@ AnthonyGeoghegan: Это не дубликат, потому что этот вопрос касается печати _chain_ символических ссылок. – mklement0
@ mklement0 Я понял это после (а затем предоставил альтернативный ответ), но я не думаю, что можно развязать. В любом случае, я оставил комментарий, поскольку ответы по соответствующему вопросу все равно были бы полезны для людей, заинтересованных в том, как разрешить символические ссылки. Отличный ответ, сам. –