我的bash脚本中有以下代码.现在我想在POSIX中使用它.那么如何转换呢?谢谢.
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )"
Run Code Online (Sandbox Code Playgroud)
mkl*_*nt0 87
POSIX-shell(sh)对应的$BASH_SOURCE是$0.请参阅底部的背景信息
警告:关键的区别在于,如果您的脚本被采购(加载到当前的 shell中.),下面 的代码段将无法正常工作.进一步解释如下
请注意,我已经改变DIR到dir在下面的代码片段,因为它是最好不要使用全部大写的变量名,以避免与环境变量和特殊shell变量冲突.
该CDPATH=前缀需要的地方> /dev/null在原来的命令:$CDPATH被设置为空字符串,以确保cd永不呼应东西.
在最简单的情况下,这将做(相当于OP的命令):
dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
Run Code Online (Sandbox Code Playgroud)
如果您还想将结果目录路径解析为其最终目标,以防目录和/或其组件是符号链接,请添加-P到pwd命令:
dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)
Run Code Online (Sandbox Code Playgroud)
警告:这是不一样的发现脚本自身起源的真正目录:
比方说,你的脚本foo被链接到/usr/local/bin/foo的$PATH,但其真正的路径/foodir/bin/foo.
上述仍将报告/usr/local/bin,因为符号链接的分辨率(-P)被应用到目录中,/usr/local/bin而不是在脚本本身.
要查找脚本自己的真实原始目录,您必须检查脚本的路径以查看它是否为符号链接,如果是,请遵循(链)符号链接到最终目标文件,然后从中提取目录路径该 目标文件的规范路径.
GNU readlink -f(更好:) readlink -e可以为您做到这一点,但readlink不是POSIX实用程序.
虽然包括OSX在内的BSD平台也有readlink实用程序,但在OSX上它不支持其-f功能.这就是说,以显示任务如何变得简单,如果 readlink -f是可用的:dir=$(dirname "$(readlink -f -- "$0")").
实际上,没有用于解析文件符号链接的POSIX实用程序.有办法解决这个问题,但它们很麻烦且不够完善:
在下面的,符合POSIX标准的shell函数实现什么GNU的readlink -e确实是一个相当强大的解决方案是唯一的失败有两种罕见的边缘情况:
->(也很少见)使用此函数named rreadlink,defined,以下内容确定脚本的真实目录路径:
dir=$(dirname -- "$(rreadlink "$0")")
Run Code Online (Sandbox Code Playgroud)
readlink 源代码 - 在脚本中调用之前放置:
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
)
Run Code Online (Sandbox Code Playgroud)
为了具有健壮性和可预测性,该函数用于rreadlink()确保仅调用shell内置函数或外部实用程序(忽略别名和函数形式的重载).
它已经:在最近版本的下列炮弹进行测试command,bash,dash,ksh.
tl;博士:
仅使用POSIX功能:
zsh,但通常不起作用zsh).sh$0zsh$0zsh$0,bash,和ksh具有非标准特征在于做允许确定实际脚本路径即使在源场景和还检测脚本是否正在来源与否; 例如,in zsh,bash 始终包含正在运行的脚本的路径,无论它是否来源,并且$BASH_SOURCE可用于测试脚本是否来源.为了说明为什么不能这样做,让我们分析Walter A答案中的命令:
# NOT recommended - see discussion below.
DIR=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )
Run Code Online (Sandbox Code Playgroud)
[[ $0 != "$BASH_SOURCE" ]]两次是多余的 - 使用它就足够了-P.pwd如果cd恰好设置了该命令,则缺少对潜在stdout输出的静默.)$CDPATH
command -v -- "$0"旨在覆盖一个额外的场景:如果脚本正在采购从交互式外壳,command -v -- "$0"通常包含单纯的文件名外壳可执行文件(的$0),在这种情况下sh会简单地返回dirname(因为这是.给定一个参数时,没有总是做路径零件).
dirname然后通过command -v -- "$0"lookup($PATH)返回该shell的绝对路径.但请注意,某些平台(例如OSX)上的登录 shell的文件名前缀为/bin/shin -($0),在这种情况下-sh不能按预期工作(返回空字符串).command -v -- "$0"两个非源方案中行为异常:
command -v -- "$0"sh可能会返回一个空字符串,这取决于具体的外壳作为command -v -- "$0"一个给定的系统上:sh,bash,并ksh返回一个空字符串; 只有zsh呼应dash$0没有明确说是否command,何时应用到文件系统路径,应该只返回可执行文件 -这是什么command -v,bash以及ksh做-但你可以认为它是由真正目的暗示zsh; 奇怪的command是,这通常是最合规的POSIX公民,在这里偏离了标准.相比之下,dash这里是唯一的模型公民,因为它是唯一一个仅报告可执行文件并按照规范要求以绝对(尽管未规范化)路径报告它们的公民.ksh,并且调用使用其纯粹的文件名(例如$PATH),sh myScript则还将返回空字符串,除了command -v -- "$0".dash$0zshsh:$0[ "$0" = "sh" ] || [ "$0" = "-sh" ] || [ "$0" = "/bin/sh" ]那时只包含了源脚本的路径.$0源场景中的有用性有限以及它打破了两个非资源场景的事实,我的投票是不使用它,这让我们:
command -v -- "$0"最终包含.无法可靠地区分当前目录中的非源调用.$dir.dirname..包含该脚本的路径,并且源代码的脚本无法确定是否是这种情况.POSIX定义的行为$0相对于外壳脚本 在这里.
本质上,$0应该反映指定的脚本文件的路径,这意味着:
$0包含绝对路径.$0仅在以下情况下包含绝对路径:
$0 (假设脚本本身是可执行的)~/bin/myScriptsh ~/bin/myScript; 在幕后,系统转换$PATH为绝对路径,然后执行它; 例如:
myScript在所有其他情况下,myScript # executes /home/jdoe/bin/myScript, for instance将反映指定的脚本路径:
$0使用脚本显式调用时,这可能只是文件名(例如sh)或相对路径(例如sh myScript)sh ./myScript- 请注意,仅仅文件名只会在其中./myScript找到脚本).在实践中,$PATH,bash,dash,并且ksh都表现出这种行为.
相比之下,POSIX不强制的值zsh时采购的脚本(使用特殊的内置实用工具$0("点")),所以你不能依赖它,并在实践中,行为跨越炮弹有所不同.
.脚本来源并期望标准化行为.
$0,bash,和dash离开ksh 不变采购脚本时,那意思$0包含主叫方的 $0价值,或者更准确的说,$0最近在尚未来源本身的调用链调用者的价值; 因此,$0可以指向shell的可执行文件或指向源代码的另一个(直接调用的)脚本的路径. $0作为唯一的反对者,实际上确实报告了当前脚本的路径zsh.相反,$0将不提供脚本是否来源的指示.$0当前脚本路径的关系是什么.$0,bash和ksh所有提供自己获取运行脚本路径的方法,即使它来源.为了完整起见:在其他情境中的价值zsh:
$0保持不变 ; 因此,无论它在函数之外有什么价值,它都有内在的.
$0,bash,和dash你的行为的方式.ksh是唯一的反对者并报告函数的名称.zsh启动选项接受命令字符串的shell中,它是设置的第一个操作数(非选项参数)-c; 例如:
$0sh -c 'echo \$0: $0 \$1: $1' foo one # -> '$0: foo $1: one',bash,dash,和ksh所有的行为是那样的.zsh是第一个参数的,所述壳的所述值父进程传递 -典型地,这就是外壳的名称或路径(例如$0,或sh); 这包括:
/bin/sh的外壳名字将它之前-,以便发出信号,告知这是一个_login壳壳; 因此,默认情况下,$0报告$0不在-bashOSX上的交互式shell中.bash)sh < myScript,bash,dash,和ksh所有的行为是那样的.| 归档时间: |
|
| 查看次数: |
7299 次 |
| 最近记录: |