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 readlink
hala 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
, ksh
vezsh
:
Ö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 bash
tek 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 unalias
veya unset
ve ne [
yapılır?
Orijinal anlamı rreadlink
olması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 unalias
ya unset
ya, 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 unalias
ve unset
onları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, bash
ve zsh
diğer adlar böylece çalıştırmalısınız kabuk anahtar kelime yinelenmesi karşı koruma için, en yüksek önceliğe sahip unalias
olan 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_aliases
açı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 \unset
sahip olmasını gerektiren bunu kullanmalısınız unset
:
unset
bir 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, unset
orijinal anlamına güvenemezseniz, anlatabileceğim kadarıyla, tüm kötü amaçlı yeniden tanımlara karşı savunmanın garantili bir yolu yoktur.