问题
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="${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
What I already know is that I can use
SCRIPT_PATH="$0"; to get the path were the script is located at. But then I get errors with the "readlink" statement.
Thanks for your help
回答1:
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:
if(…)andwhile(…)launch…in a subshell. You do not need subshell here, it is faster to do these checks using justif …andwhile ….pushd .is not needed at all. While usingpushdyou normally replace thecdcall with it:pushd "$(dirname $SCRIPT_PATH)" >/dev/null SCRIPT_PATH="$(pwd)" popd >/dev/nullcd `…`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.- You do not need trailing
;in variable declarations. - There is
readlink -fthat will resolve all symlinks thus you may consider reducing original script toSCRIPT_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}. if [ -h "$SCRIPT_PATH" ]is redundant sincewhilebody with the same condition will not be executed unless script path is a symlink.readlink $SCRIPT_PATHwill return symlink relative to the directory containing$SCRIPT_PATH. Thus original script cannot possibly used to resolve symlinks in last component.- There is no
;betweenif(…)andthen. 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:
- Create directory
$R/bash($Ris any directory, e.g./tmp). - Put your script there without modifications, e.g. under name
$R/bash/script_path.bash. Add lineecho "$SCRIPT_PATH"at the end of it and line#!/bin/bashat the start for testing. - Make it executable:
chmod +x $R/bash/script_path.bash. - Create a symlink to it:
cd $R/bash && ln -s script_path.bash link. cd $R- Launch
$R/bash/1. Now you will see that your script outputs$Rwhile it should output$R/bashlike it does when you launch$R/bash/script_path.bash.
来源:https://stackoverflow.com/questions/18810483/what-is-the-zsh-equivalent-of-a-bash-script-getting-the-scripts-directory