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

前端 未结 1 1053
余生分开走
余生分开走 2021-01-15 23:55

I want to translate this bash-script intro a zsh-script. Hence I have no experience with this I hope I may get help here:

bash script:

SCRIPT_PATH=\         


        
相关标签:
1条回答
  • 2021-01-16 00:41

    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.
    0 讨论(0)
提交回复
热议问题