关于bash:如何在MacOS上获取shell脚本的绝对路径名?

How to get absolute path name of shell script on MacOS?

MacOS上不存在readlink -f。对于我在网上找到的Mac OS,唯一可行的解决方案是:

1
2
3
4
5
if [[ $(echo $0 | awk '/^\//') == $0 ]]; then
    ABSPATH=$(dirname $0)
else
    ABSPATH=$PWD/$(dirname $0)
fi

对于这个看似微不足道的任务,有人能提出更优雅的建议吗?


另一个(所以不是丑女)选项:

1
ABSPATH=$(cd"$(dirname"$0")"; pwd)


shell脚本的绝对路径(get

挖出来。那些从我的一些旧的脚本语法A位,和更新,增加了一个测试套件。

支持

  • 源代码/脚本(时称为"由.点操作符)
  • 绝对路径路径/到/脚本
  • 相对路径/脚本类。
  • dir1 /路径/ / / / / / dir2 dir3脚本。
  • 当被从链接
  • 当链接是嵌套foo->dir1/dir2/bar bar->./../doe doe->scriptEC)
  • 当呼叫者的名字更改脚本

它已经进行了测试,使用真实的项目和成功案例,然而,有可能是我不知道的角落。如果你能找到这样一个情况,请让我知道。(一),我知道这是不运行在SH壳)

代码

1
2
3
4
5
6
7
8
9
10
11
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`]"

已知的问题

脚本必须在磁盘的某个地方,让它过的网络。如果你尝试运行脚本从一管它不工作

1
wget -o /dev/null -O - http://host.domain/dir/script.sh |bash

从技术上讲,它是不明确的。我们几乎没有理智的方式,来检测本。

使用测试用例

这是检查测试用例流和它的作品。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#!/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


本方法使用bash I suggest。你的第一个光盘的目录,然后你把当前目录使用PWD。返回后,你必须确保你的旧目录的脚本创建一个侧不影响其他脚本调用它。

1
2
3
4
cd"$(dirname --"$0")"
dir="$PWD"
echo"$dir"
cd - > /dev/null

这个解决方案是安全的和复杂的路径。你将永远不会有麻烦与空间的特殊性或如果你把引号。

注:/dev/null是需要"CD"或打印它的返回路径。


所以注意homebrew"(http://brew.sh realpath(链接)coreutils包包括了in/opt/local/bin)。

1
2
$ realpath bin
/Users/nhed/bin

我发现这很有用的符号链接与动态链接的作品/ GNU readlink(只因为我个F标志):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# detect if GNU readlink is available on OS X
if ["$(uname)" ="Darwin" ]; then
  which greadlink > /dev/null || {
    printf 'GNU readlink not found
'

    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

你可以尝试在你的脚本是这样的吗?

1
echo $(pwd)/"$0"

在我的机器它的显示:

1
/home/barun/codes/ns2/link_down/./test.sh

这是绝对路径名的shell脚本。


如果你不使用Perl:心灵

1
ABSPATH=$(perl -MCwd=realpath -e"print realpath '$0'")


我使用下面的函数来emulate"情况下,F’的脚本有两个运行在Linux和Mac OS X。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/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的输出目标。

1
2
3
4
5
$ ./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是一个目标输出。

1
2
3
4
5
$ ./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


如果你使用的是${.sh.file}ksh,参数集的绝对路径名的脚本。得到父目录的脚本:${.sh.file%/*}


本作品,只要它不是一个链接,和一marginally:也不丑

1
ABSPATH=$(dirname $(pwd -P $0)/${0#\.\/})

这是我在这里使用,可能需要调整或有a

1
2
3
4
5
6
7
8
9
10
11
12
abspath ()
{
    case"${1}" in
        [./]*)
            local ABSPATH="$(cd ${1%/*}; pwd)/${1##*/}"
            echo"${ABSPATH/\/\///}"
        ;;
        *)
            echo"${PWD}/${1}"
        ;;
    esac
}

这是在所有的文件和你可以诅咒它abspath ${0}invoke

第一个案例交易相对路径的路径由CD - ING和PWD图让它

在第二个案例是一个本地文件处理(在# # } { 1美元/人没有工作)

这对于符号链接不会松开。