例子:

absolute="/foo/bar"
current="/foo/baz/foo"

# Magic

relative="../../bar"

我如何创造魔法(希望不是太复杂的代码…)?


当前回答

$ python -c "import os.path; print os.path.relpath('/foo/bar', '/foo/baz/foo')"

给:

../../bar

其他回答

test.sh:

#!/bin/bash                                                                 

cd /home/ubuntu
touch blah
TEST=/home/ubuntu/.//blah
echo TEST=$TEST
TMP=$(readlink -e "$TEST")
echo TMP=$TMP
REL=${TMP#$(pwd)/}
echo REL=$REL

测试:

$ ./test.sh 
TEST=/home/ubuntu/.//blah
TMP=/home/ubuntu/blah
REL=blah

该脚本仅对绝对路径或没有绝对路径的相对路径的输入提供正确的结果。或者. .:

#!/bin/bash

# usage: relpath from to

if [[ "$1" == "$2" ]]
then
    echo "."
    exit
fi

IFS="/"

current=($1)
absolute=($2)

abssize=${#absolute[@]}
cursize=${#current[@]}

while [[ ${absolute[level]} == ${current[level]} ]]
do
    (( level++ ))
    if (( level > abssize || level > cursize ))
    then
        break
    fi
done

for ((i = level; i < cursize; i++))
do
    if ((i > level))
    then
        newpath=$newpath"/"
    fi
    newpath=$newpath".."
done

for ((i = level; i < abssize; i++))
do
    if [[ -n $newpath ]]
    then
        newpath=$newpath"/"
    fi
    newpath=$newpath${absolute[i]}
done

echo "$newpath"

自2001年以来,它被内置到Perl中,因此它几乎可以在您能想象到的所有系统上工作,甚至VMS。

perl -le 'use File::Spec; print File::Spec->abs2rel(@ARGV)' FILE BASE

而且,解决方案很容易理解。

举个例子:

perl -le 'use File::Spec; print File::Spec->abs2rel(@ARGV)' $absolute $current

...会很好。

kasku和Pini的答案略有改进,空格更好,允许传递相对路径:

#!/bin/bash
# both $1 and $2 are paths
# returns $2 relative to $1
absolute=`readlink -f "$2"`
current=`readlink -f "$1"`
# Perl is magic
# Quoting horror.... spaces cause problems, that's why we need the extra " in here:
relative=$(perl -MFile::Spec -e "print File::Spec->abs2rel(q($absolute),q($current))")

echo $relative

我将只使用Perl来完成这个不那么简单的任务:

absolute="/foo/bar"
current="/foo/baz/foo"

# Perl is magic
relative=$(perl -MFile::Spec -e 'print File::Spec->abs2rel("'$absolute'","'$current'")')