readlink -f
。我设法在网上找到的唯一可用的Mac OS解决方案是:
if [[ $(echo $0 | awk '/^\//') == $0 ]]; then
ABSPATH=$(dirname $0)
else
ABSPATH=$PWD/$(dirname $0)
fi
任何人都可以向这个看似微不足道的任务提出更优雅的建议吗?
答案 0 :(得分:62)
另一个(也很丑陋)选项:
ABSPATH=$(cd "$(dirname "$0")"; pwd)
答案 1 :(得分:9)
从我的.bashrc挖出一些旧脚本,并稍微更新了语法,添加了一个测试套件。
.
点运算符调用时)foo->dir1/dir2/bar bar->./../doe doe->script
它已在实际项目中经过测试并成功使用,但可能存在我不知道的极端情况 如果您能够找到这种情况,请告诉我 (首先,我知道这不会在sh shell上运行)
pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}";
while([ -h "${SCRIPT_PATH}" ]) do
cd "`dirname "${SCRIPT_PATH}"`"
SCRIPT_PATH="$(readlink "`basename "${SCRIPT_PATH}"`")";
done
cd "`dirname "${SCRIPT_PATH}"`" > /dev/null
SCRIPT_PATH="`pwd`";
popd > /dev/null
echo "srcipt=[${SCRIPT_PATH}]"
echo "pwd =[`pwd`]"
脚本必须位于磁盘上,让它通过网络。 如果您尝试从PIPE运行此脚本,它将无法正常工作
wget -o /dev/null -O - http://host.domain/dir/script.sh |bash
从技术上讲,它是未定义的 实际上,没有理智的方法来检测这一点。
当前的测试用例,检查它是否有效。
#!/bin/bash
# setup test enviroment
mkdir -p dir1/dir2
mkdir -p dir3/dir4
ln -s ./dir1/dir2/foo bar
ln -s ./../../dir3/dir4/test.sh dir1/dir2/foo
ln -s ./dir1/dir2/foo2 bar2
ln -s ./../../dir3/dir4/doe dir1/dir2/foo2
cp test.sh ./dir1/dir2/
cp test.sh ./dir3/dir4/
cp test.sh ./dir3/dir4/doe
P="`pwd`"
echo "--- 01"
echo "base =[${P}]" && ./test.sh
echo "--- 02"
echo "base =[${P}]" && `pwd`/test.sh
echo "--- 03"
echo "base =[${P}]" && ./dir1/dir2/../../test.sh
echo "--- 04"
echo "base =[${P}/dir3/dir4]" && ./bar
echo "--- 05"
echo "base =[${P}/dir3/dir4]" && ./bar2
echo "--- 06"
echo "base =[${P}/dir3/dir4]" && `pwd`/bar
echo "--- 07"
echo "base =[${P}/dir3/dir4]" && `pwd`/bar2
echo "--- 08"
echo "base =[${P}/dir1/dir2]" && `pwd`/dir3/dir4/../../dir1/dir2/test.sh
echo "--- 09"
echo "base =[${P}/dir1/dir2]" && ./dir1/dir2/test.sh
echo "--- 10"
echo "base =[${P}/dir3/dir4]" && ./dir3/dir4/doe
echo "--- 11"
echo "base =[${P}/dir3/dir4]" && ./dir3/dir4/test.sh
echo "--- 12"
echo "base =[${P}/dir3/dir4]" && `pwd`/dir3/dir4/doe
echo "--- 13"
echo "base =[${P}/dir3/dir4]" && `pwd`/dir3/dir4/test.sh
echo "--- 14"
echo "base =[${P}/dir3/dir4]" && `pwd`/dir1/dir2/../../dir3/dir4/doe
echo "--- 15"
echo "base =[${P}/dir3/dir4]" && `pwd`/dir1/dir2/../../dir3/dir4/test.sh
echo "--- 16"
echo "base s=[${P}]" && source test.sh
echo "--- 17"
echo "base s=[${P}]" && source `pwd`/test.sh
echo "--- 18"
echo "base s=[${P}/dir1/dir2]" && source ./dir1/dir2/test.sh
echo "--- 19"
echo "base s=[${P}/dir3/dir4]" && source ./dir1/dir2/../../dir3/dir4/test.sh
echo "--- 20"
echo "base s=[${P}/dir3/dir4]" && source `pwd`/dir1/dir2/../../dir3/dir4/test.sh
echo "--- 21"
pushd . >/dev/null
cd ..
echo "base x=[${P}/dir3/dir4]"
./`basename "${P}"`/bar
popd >/dev/null
PurpleFox又名GreenFox
答案 2 :(得分:3)
使用bash我建议这种方法。首先cd到目录,然后使用pwd获取当前目录。之后,您必须返回旧目录,以确保您的脚本不会为调用它的其他脚本创建副作用。
cd "$(dirname -- "$0")"
dir="$PWD"
echo "$dir"
cd - > /dev/null
这种解决方案在复杂路径下是安全的。如果你把引号放在一边,你就永远不会有空格或特殊字符的麻烦。
注意:/ dev / null是require或“cd - ”打印返回的路径。
答案 3 :(得分:2)
另请注意,homebrew
的{{3}})coreutils
个套餐包含realpath
(/opt/local/bin
中创建的链接)。
$ realpath bin
/Users/nhed/bin
答案 4 :(得分:1)
如果你不介意使用perl:
ABSPATH=$(perl -MCwd=realpath -e "print realpath '$0'")
答案 5 :(得分:1)
你能在剧本中尝试这样的东西吗?
echo $(pwd)/"$0"
在我的机器中显示:
/home/barun/codes/ns2/link_down/./test.sh
这是shell脚本的绝对路径名。
答案 6 :(得分:1)
我发现这对符号链接/动态链接很有用 - 仅适用于GNU readlink(因为-f标志):
# detect if GNU readlink is available on OS X
if [ "$(uname)" = "Darwin" ]; then
which greadlink > /dev/null || {
printf 'GNU readlink not found\n'
exit 1
}
alias readlink="greadlink"
fi
# create a $dirname variable that contains the file dir
dirname=$(dirname "$(readlink -f "$0")")
# use $dirname to find a relative file
cat "$dirname"/foo/bar.txt
答案 7 :(得分:0)
这是我使用的,可能需要在这里或那里进行调整
abspath ()
{
case "${1}" in
[./]*)
local ABSPATH="$(cd ${1%/*}; pwd)/${1##*/}"
echo "${ABSPATH/\/\///}"
;;
*)
echo "${PWD}/${1}"
;;
esac
}
这适用于任何文件 - 您可以将其作为abspath ${0}
第一种情况通过cd-ing到路径来处理相对路径并让pwd弄明白
第二种情况是处理本地文件($ {1 ## /}不起作用)
这不会尝试撤消符号链接!
答案 8 :(得分:0)
只要它不是符号链接,它就可以工作,并且可能稍微不那么难看:
ABSPATH=$(dirname $(pwd -P $0)/${0#\.\/})
答案 9 :(得分:0)
如果您使用的是ksh,${.sh.file}
参数将设置为脚本的绝对路径名。获取脚本的父目录:${.sh.file%/*}
答案 10 :(得分:0)
我使用下面的函数来模拟" readlink -f"对于必须在Linux和Mac OS X上运行的脚本。
#!/bin/bash
# This was re-worked on 2018-10-26 after der@build correctly
# observed that the previous version did not work.
# Works on both linux and Mac OS X.
# The "pwd -P" re-interprets all symlinks.
function read-link() {
local path=$1
if [ -d $path ] ; then
local abspath=$(cd $path; pwd -P)
else
local prefix=$(cd $(dirname -- $path) ; pwd -P)
local suffix=$(basename $path)
local abspath="$prefix/$suffix"
fi
if [ -e $abspath ] ; then
echo $abspath
else
echo 'error: does not exist'
fi
}
# Example usage.
while (( $# )) ; do
printf '%-24s - ' "$1"
read-link $1
shift
done
这是一些常见的Mac OS X目标的输出:
$ ./example.sh /usr/bin/which /bin/which /etc/racoon ~/Downloads
/usr/bin/which - /usr/bin/which
/bin/which - error: does not exist
/etc/racoon - /private/etc/racoon
/Users/jlinoff/Downloads - /Users/jlinoff/Downloads
这是一些linux目标的输出。
$ ./example.sh /usr/bin/which /bin/whichx /etc/init.d ~/Downloads
/usr/bin/which - /usr/bin/which
/bin/whichx - error: does not exist
/etc/init.d - /etc/init.d
/home/jlinoff/Downloads - /home/jlinoff/Downloads