一个bash脚本获取脚本所在目录的zsh等效命令是什么?

8
我希望您能将这个bash脚本翻译成zsh脚本。因此,我没有相关经验,希望在这里得到帮助:
bash脚本:
SCRIPT_PATH="${BASH_SOURCE[0]}";
if([ -h "${SCRIPT_PATH}" ]) then
    while([ -h "${SCRIPT_PATH}" ]) do SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
fi
pushd . > /dev/null
cd `dirname ${SCRIPT_PATH}` > /dev/null
SCRIPT_PATH=`pwd`;
popd  > /dev/null

我已经知道我可以使用SCRIPT_PATH="$0";来获取脚本所在的路径。但是,然后我使用"readlink"语句时会出现错误。

感谢您的帮助。


2
运行时加上“-x”参数,以打印出哪些变量被定义(或未定义),从那里开始调试。你的脚本很短且简单 - 不应该难。在我看来... - paulsm4
1个回答

22

除了BASH_SOURCE,我没有看到你需要进行任何更改。但是这个脚本的目的是什么?如果你想要获取脚本所在的目录,可以使用${0:A:h}:A将解析所有符号链接,:h将截断最后一个路径组件,只留下目录名):

SCRIPT_PATH="${0:A:h}"

这就是全部内容。请注意,原始脚本中有一些奇怪的地方:

  1. if(...)while(...) 会在子Shell 中启动 ...。您不需要在此使用子Shell,只需使用 if ...while ... 即可更快速地执行这些检查。
  2. pushd . 完全没有必要。在使用 pushd 时,您通常会用它替换 cd 调用:

    pushd "$(dirname $SCRIPT_PATH)" >/dev/null
    SCRIPT_PATH="$(pwd)"
    popd >/dev/null
    
  3. cd `…`如果输出带有空格的内容,则会失败。目录中可能包含空格。在上面的示例中,我使用"$(…)""`…`"也可以。
  4. 变量声明中不需要尾随;
  5. readlink -f将解析所有符号链接,因此您可以考虑将原始脚本简化为SCRIPT_PATH="$(dirname $(readlink -f "${BASH_SOURCE[0]}"))"(行为可能会更改,因为您的脚本似乎仅解析最后一个组件中的符号链接):这是bash等同于${0:A:h}
  6. if [ -h "$SCRIPT_PATH" ]是多余的,因为只有在脚本路径是符号链接时,才会执行具有相同条件的while体。
  7. readlink $SCRIPT_PATH将返回相对于包含$SCRIPT_PATH的目录的符号链接。因此,原始脚本不可能用于解析最后一个组件中的符号链接。
  8. if(…)then之间没有;。我很惊讶bash能接受这个。

上述所有语句都适用于bash和zsh。

如果仅解析最后一个组件中的符号链接很重要,您应该这样编写:

SCRIPT_PATH="$0:a"
function ResolveLastComponent()
{
    pushd "$1:h" >/dev/null
    local R="$(readlink "$1")"
    R="$R:a"
    popd >/dev/null
    echo $R
}
while test -h "$SCRIPT_PATH" ; do
    SCRIPT_PATH="$(ResolveLastComponent "$SCRIPT_PATH")"
done

为了说明第七个声明,以下是一个例子:

  1. 创建目录$R/bash$R可以是任何目录,例如/tmp)。
  2. 在该目录下放置您的脚本(无需修改),例如将其命名为$R/bash/script_path.bash。在结尾添加代码行echo "$SCRIPT_PATH",并在开头添加#!/bin/bash进行测试。
  3. 将脚本变成可执行文件:chmod +x $R/bash/script_path.bash
  4. 创建到它的符号链接:cd $R/bash && ln -s script_path.bash link
  5. cd $R
  6. 启动$R/bash/1。现在您会发现您的脚本输出$R,而实际上应该输出$R/bash,就像当您启动$R/bash/script_path.bash时一样。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接