Not: Bunun sağlam, taşınabilir, hazır bir çözüm olduğuna inanıyorum, bu nedenle bu nedenle her zaman uzun .
Aşağıda, tamamen çapraz platform olan POSIX uyumlu bir komut dosyası / işlev bulunmaktadır (10.12 (Sierra) itibariyle readlinkhala desteklemeyen macOS üzerinde de çalışır -f) - yalnızca POSIX kabuk dili özelliklerini ve yalnızca POSIX uyumlu yardımcı program çağrılarını kullanır .
Bu bir olan GNU en taşınabilir uygulamareadlink -e (daha sıkı sürümü readlink -f).
Sen edebilirsiniz çalıştırmak komut ilesh veya kaynak işlevi de bash, kshvezsh :
Örneğin, bir komut dosyasının içinde, sembolik bağlantıların çözülmesiyle çalışan komut dosyasının gerçek başlangıç dizinini almak için aşağıdaki gibi kullanabilirsiniz:
trueScriptDir=$(dirname -- "$(rreadlink "$0")")
rreadlink kod / fonksiyon tanımı:
Kod bu cevaptan şükranla uyarlandı .
Ayrıca burada Node.js yüklüyse, yükleyebileceğiniz bashtek tabanlı bir yardımcı program sürümü oluşturdum .
npm install rreadlink -g
#!/bin/sh
# SYNOPSIS
# rreadlink <fileOrDirPath>
# DESCRIPTION
# Resolves <fileOrDirPath> to its ultimate target, if it is a symlink, and
# prints its canonical path. If it is not a symlink, its own canonical path
# is printed.
# A broken symlink causes an error that reports the non-existent target.
# LIMITATIONS
# - Won't work with filenames with embedded newlines or filenames containing
# the string ' -> '.
# COMPATIBILITY
# This is a fully POSIX-compliant implementation of what GNU readlink's
# -e option does.
# EXAMPLE
# In a shell script, use the following to get that script's true directory of origin:
# trueScriptDir=$(dirname -- "$(rreadlink "$0")")
rreadlink() ( # Execute the function in a *subshell* to localize variables and the effect of `cd`.
target=$1 fname= targetDir= 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 # Resolve potential symlinks until the ultimate target is found.
[ -L "$target" ] || [ -e "$target" ] || { command printf '%s\n' "ERROR: '$target' does not exist." >&2; return 1; }
command cd "$(command dirname -- "$target")" # Change to target dir; necessary for correct resolution of target path.
fname=$(command basename -- "$target") # Extract filename.
[ "$fname" = '/' ] && fname='' # !! curiously, `basename /` returns '/'
if [ -L "$fname" ]; then
# Extract [next] target path, which may be defined
# *relative* to the symlink's own directory.
# Note: We parse `ls -l` output to find the symlink target
# which is the only POSIX-compliant, albeit somewhat fragile, way.
target=$(command ls -l "$fname")
target=${target#* -> }
continue # Resolve [next] symlink target.
fi
break # Ultimate target reached.
done
targetDir=$(command pwd -P) # Get canonical dir. path
# Output the ultimate target's canonical path.
# Note that we manually resolve paths ending in /. and /.. to make sure we have a normalized path.
if [ "$fname" = '.' ]; then
command printf '%s\n' "${targetDir%/}"
elif [ "$fname" = '..' ]; then
# Caveat: something like /var/.. will resolve to /private (assuming /var@ -> /private/var), i.e. the '..' is applied
# AFTER canonicalization.
command printf '%s\n' "$(command dirname -- "${targetDir}")"
else
command printf '%s\n' "${targetDir%/}/$fname"
fi
)
rreadlink "$@"
Güvenlik teğetliği:
jarno , yerleşkenincommand aynı ada sahip bir takma ad veya kabuk işlevi tarafından gölgelenmemesini sağlayan işleve istinaden bir yorumda bulunur:
Ya takma adlar veya kabuk işlevleri olarak ayarlanırsa unaliasveya unsetve ne [yapılır?
Orijinal anlamı rreadlinkolmasını sağlamanın ardındaki motivasyon command, onu yeniden tanımlamak gibi etkileşimli kabuklarda standart komutları gölgelemek için sıklıkla kullanılan kullanışlı takma adları ve işlevleri atlamak (benign) kullanmaktır.ls seçenekleri içermek .
Bunun endişesi, güvenilmeyen, kötü niyetli çevre ile o sürece ediyoruz konu işlemi söylemek güvenli olduğunu düşünüyorum unaliasya unsetya, bu konuda, - while, do... - yeniden belirlendiği bir endişe değildir.
Orada bir şey fonksiyonu orijinal anlam ve davranış olması güvenmek gerektiğini - etrafta hiçbir yolu yoktur.
POSIX benzeri mermilerin yerleşiklerin ve hatta dil anahtar kelimelerinin yeniden tanımlanmasına izin vermesi doğal olarak bir güvenlik riskidir (ve genel olarak paranoyak kod yazmak zordur).
Endişelerinizi özellikle ele almak için:
Fonksiyon orijinal anlamlarına dayanır unaliasve unsetonların orijinal anlamlarına sahiptir. Kabuk işlevleri olarak davranışlarını değiştirecek şekilde yeniden tanımlanması bir sorun olacaktır; bir takma ad olarak yeniden tanımlanması bir endişe kaynağı değildir, çünkü komut adının (ör.) alıntılanması (örneğin \unalias) takma adları atlar.
Ancak, alıntı olduğu değil kabuk için bir seçenek anahtar kelimeler ( while, for, if, do, ...) ve kabuk anahtar kabuk üzerinde öncelik taşır yaparken fonksiyonları içinde, bashve zshdiğer adlar böylece çalıştırmalısınız kabuk anahtar kelime yinelenmesi karşı koruma için, en yüksek önceliğe sahip unaliasolan isimleri (her ne kadar etkileşimli olmayan bash Script gibi kabukları () diğer adları olan değil , varsayılan olarak genişletilmiş - yalnızca shopt -s expand_aliasesaçıkça ilk olarak adlandırılır).
unalias- Bir yerleşik olarak - orijinal anlamına sahip olduğundan emin olmak için , önce orijinal anlamına \unsetsahip olmasını gerektiren bunu kullanmalısınız unset:
unsetbir kabuk yerleşiktir , bu yüzden çağrıldığından emin olmak için kendisinin bir işlev olarak yeniden tanımlanmadığından emin olmanız gerekir. . Diğer ad formunu tırnak işareti ile atlayabilirken, kabuk işlevi formunu atlayamazsınız - catch 22.
Bu nedenle, unsetorijinal anlamına güvenemezseniz, anlatabileceğim kadarıyla, tüm kötü amaçlı yeniden tanımlara karşı savunmanın garantili bir yolu yoktur.