是否有一个命令来检索给定相对路径的绝对路径?

例如,我想要$line包含dir ./etc/中每个文件的绝对路径

find ./ -type f | while read line; do
   echo $line
done

当前回答

我最喜欢的解决方案是@EugenKonkov的解决方案,因为它没有暗示其他实用程序的存在(coreutils包)。

但是对于相对路径“.”和“..”它失败了,所以这里有一个稍微改进的版本来处理这些特殊情况。

但是,如果用户没有cd到相对路径的父目录的权限,它仍然会失败。

#! /bin/sh

# Takes a path argument and returns it as an absolute path. 
# No-op if the path is already absolute.
function to-abs-path {
    local target="$1"

    if [ "$target" == "." ]; then
        echo "$(pwd)"
    elif [ "$target" == ".." ]; then
        echo "$(dirname "$(pwd)")"
    else
        echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
    fi
}

其他回答

echo "mydir/doc/ mydir/usoe ./mydir/usm" |  awk '{ split($0,array," "); for(i in array){ system("cd "array[i]" && echo $PWD") } }'

如果你想将一个包含相对路径的变量转换为绝对路径,这是可行的:

   dir=`cd "$dir"`

"cd"在不改变工作目录的情况下被回显,因为它是在子shell中执行的。

这是来自所有其他解决方案的链式解决方案,例如,当realpath失败时,要么是因为没有安装它,要么是因为它带着错误代码退出,那么,将尝试下一个解决方案,直到它获得正确的路径。

#!/bin/bash

function getabsolutepath() {
    local target;
    local changedir;
    local basedir;
    local firstattempt;

    target="${1}";
    if [ "$target" == "." ];
    then
        printf "%s" "$(pwd)";

    elif [ "$target" == ".." ];
    then
        printf "%s" "$(dirname "$(pwd)")";

    else
        changedir="$(dirname "${target}")" && basedir="$(basename "${target}")" && firstattempt="$(cd "${changedir}" && pwd)" && printf "%s/%s" "${firstattempt}" "${basedir}" && return 0;
        firstattempt="$(readlink -f "${target}")" && printf "%s" "${firstattempt}" && return 0;
        firstattempt="$(realpath "${target}")" && printf "%s" "${firstattempt}" && return 0;

        # If everything fails... TRHOW PYTHON ON IT!!!
        local fullpath;
        local pythoninterpreter;
        local pythonexecutables;
        local pythonlocations;

        pythoninterpreter="python";
        declare -a pythonlocations=("/usr/bin" "/bin");
        declare -a pythonexecutables=("python" "python2" "python3");

        for path in "${pythonlocations[@]}";
        do
            for executable in "${pythonexecutables[@]}";
            do
                fullpath="${path}/${executable}";

                if [[ -f "${fullpath}" ]];
                then
                    # printf "Found ${fullpath}\\n";
                    pythoninterpreter="${fullpath}";
                    break;
                fi;
            done;

            if [[ "${pythoninterpreter}" != "python" ]];
            then
                # printf "Breaking... ${pythoninterpreter}\\n"
                break;
            fi;
        done;

        firstattempt="$(${pythoninterpreter} -c "import os, sys; print( os.path.abspath( sys.argv[1] ) );" "${target}")" && printf "%s" "${firstattempt}" && return 0;
        # printf "Error: Could not determine the absolute path!\\n";
        return 1;
    fi
}

printf "\\nResults:\\n%s\\nExit: %s\\n" "$(getabsolutepath "./asdfasdf/ asdfasdf")" "${?}"

对@ernest-a相当不错的版本的改进:

absolute_path() {
    cd "$(dirname "$1")"
    case $(basename $1) in
        ..) echo "$(dirname $(pwd))";;
        .)  echo "$(pwd)";;
        *)  echo "$(pwd)/$(basename $1)";;
    esac
}

这正确地处理了路径的最后一个元素是..,在这种情况下,@ernest-a的答案中的“$(pwd)/$(basename“$1”)”将通过作为accurate_sub_path/spurious_subdirectory/…

不管怎样,我投票给了被选中的答案,但我想分享一个解决方案。缺点是,它只适用于Linux——在出现堆栈溢出之前,我花了大约5分钟的时间试图找到OSX的等效版本。但我相信它就在那里。

在Linux上,可以将readlink -e与dirname结合使用。

$(dirname $(readlink -e ../../../../etc/passwd))

收益率

/etc/

然后你用dirname的姐妹,basename 文件名

$(basename ../../../../../passwd)

收益率

passwd

把它们放在一起…

F=../../../../../etc/passwd
echo "$(dirname $(readlink -e $F))/$(basename $F)"

收益率

/etc/passwd

如果目标目录是安全的,basename将不会返回任何内容 在最终输出中,你只会得到双斜杠。