What is the zsh equivalent of a bash script getting the script's directory?

夙愿已清 提交于 2019-12-02 03:31:55

Except for BASH_SOURCE I see no changes that you need to make. But what is the purpose of the script? If you want to get directory your script is located at there is ${0:A:h} (:A will resolve all symlinks, :h will truncate last path component leaving you with a directory name):

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

and that’s all. Note that original script has something strange going on:

  1. if(…) and while(…) launch in a subshell. You do not need subshell here, it is faster to do these checks using just if … and while ….
  2. pushd . is not needed at all. While using pushd you normally replace the cd call with it:

    pushd "$(dirname $SCRIPT_PATH)" >/dev/null
    SCRIPT_PATH="$(pwd)"
    popd >/dev/null
    
  3. cd `…` will fail if outputs something with spaces. It is possible for a directory to contain a space. In the above example I use "$(…)", "`…`" will also work.
  4. You do not need trailing ; in variable declarations.
  5. There is readlink -f that will resolve all symlinks thus you may consider reducing original script to SCRIPT_PATH="$(dirname $(readlink -f "${BASH_SOURCE[0]}"))" (the behavior may change as your script seems to resolve symlinks only in last component): this is bash equivalent to ${0:A:h}.
  6. if [ -h "$SCRIPT_PATH" ] is redundant since while body with the same condition will not be executed unless script path is a symlink.
  7. readlink $SCRIPT_PATH will return symlink relative to the directory containing $SCRIPT_PATH. Thus original script cannot possibly used to resolve symlinks in last component.
  8. There is no ; between if(…) and then. I am surprised bash accepts this.

All of the above statements apply both to bash and zsh.

If resolving only symlinks only in last component is essential you should write it like this:

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

.


To illustrate 7th statement there is the following example:

  1. Create directory $R/bash ($R is any directory, e.g. /tmp).
  2. Put your script there without modifications, e.g. under name $R/bash/script_path.bash. Add line echo "$SCRIPT_PATH" at the end of it and line #!/bin/bash at the start for testing.
  3. Make it executable: chmod +x $R/bash/script_path.bash.
  4. Create a symlink to it: cd $R/bash && ln -s script_path.bash link.
  5. cd $R
  6. Launch $R/bash/1. Now you will see that your script outputs $R while it should output $R/bash like it does when you launch $R/bash/script_path.bash.
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!