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

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

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

当前回答

下面是一个相当短的函数,可以用来完全绝对化和规范化任何给定的输入路径,只使用POSIX shell和readlink语义:

canonicalize_path() {
    (
        FILEPATH="$1"
        for _ in 1 2 3 4 5 6 7 8;  # Maximum symlink recursion depth
        do
            cd -L "`case "${FILEPATH}" in */*) echo "${FILEPATH%/*}";; *) echo ".";; esac`/"  # cd $(dirname)
            if ! FILEPATH="$(readlink "${FILEPATH##*/}" || ( echo "${FILEPATH##*/}" && false ) )";
            then
                break
            fi
        done
        cd -P "." || return $?
        echo "$(pwd)/${FILEPATH}"
    )
}

如果引用的文件不存在,则只解析指向最终文件名的目录路径。如果指向该文件路径的任何目录都不存在,将返回一个cd错误。这恰好是它试图模拟的GNU/Linux readlink -f命令的确切语义。

在bash/zsh中,您还可以将数字列表压缩为{1..8}或类似的。之所以选择8这个数字,是因为这是Linux多年来的最大限制,后来在4.2版本中将整个路径的分辨率限制为40。如果达到了分辨率限制,代码不会失败,而是返回最后考虑的路径——但是可以添加显式的[- l "${FILEPATH}"]检查来检测这种情况。

这段代码也可以很容易地重用,以确保当前工作目录与已执行脚本在文件系统中的位置匹配(shell脚本的常见需求),只需删除函数和子shell包装器:

FILEPATH="$0"
for _ in 1 2 3 4 5 6 7 8;  # Maximum symlink recursion depth
do
    cd -L "`case "${FILEPATH}" in */*) echo "${FILEPATH%/*}";; *) echo ".";; esac`/"  # cd $(dirname)
    if ! FILEPATH="$(readlink "${FILEPATH##*/}" || ( echo "${FILEPATH##*/}" && false ) )";
    then
        break
    fi
done
cd -P "."
FILEPATH="$(pwd)/${FILEPATH}"

其他回答

在find的情况下,可能最简单的是给它搜索的绝对路径,例如:

find /etc
find `pwd`/subdir_of_current_dir/ -type f

类似于@ernest-a的答案,但不影响$OLDPWD或定义一个新函数,您可以触发一个子shell (cd <path>;pwd)

$ pwd
/etc/apache2
$ cd ../cups 
$ cd -
/etc/apache2
$ (cd ~/..; pwd)
/Users
$ cd -
/etc/cups

下面是一个相当短的函数,可以用来完全绝对化和规范化任何给定的输入路径,只使用POSIX shell和readlink语义:

canonicalize_path() {
    (
        FILEPATH="$1"
        for _ in 1 2 3 4 5 6 7 8;  # Maximum symlink recursion depth
        do
            cd -L "`case "${FILEPATH}" in */*) echo "${FILEPATH%/*}";; *) echo ".";; esac`/"  # cd $(dirname)
            if ! FILEPATH="$(readlink "${FILEPATH##*/}" || ( echo "${FILEPATH##*/}" && false ) )";
            then
                break
            fi
        done
        cd -P "." || return $?
        echo "$(pwd)/${FILEPATH}"
    )
}

如果引用的文件不存在,则只解析指向最终文件名的目录路径。如果指向该文件路径的任何目录都不存在,将返回一个cd错误。这恰好是它试图模拟的GNU/Linux readlink -f命令的确切语义。

在bash/zsh中,您还可以将数字列表压缩为{1..8}或类似的。之所以选择8这个数字,是因为这是Linux多年来的最大限制,后来在4.2版本中将整个路径的分辨率限制为40。如果达到了分辨率限制,代码不会失败,而是返回最后考虑的路径——但是可以添加显式的[- l "${FILEPATH}"]检查来检测这种情况。

这段代码也可以很容易地重用,以确保当前工作目录与已执行脚本在文件系统中的位置匹配(shell脚本的常见需求),只需删除函数和子shell包装器:

FILEPATH="$0"
for _ in 1 2 3 4 5 6 7 8;  # Maximum symlink recursion depth
do
    cd -L "`case "${FILEPATH}" in */*) echo "${FILEPATH%/*}";; *) echo ".";; esac`/"  # cd $(dirname)
    if ! FILEPATH="$(readlink "${FILEPATH##*/}" || ( echo "${FILEPATH##*/}" && false ) )";
    then
        break
    fi
done
cd -P "."
FILEPATH="$(pwd)/${FILEPATH}"

你可以使用bash字符串替换任何相对路径$line:

line=$(echo ${line/#..\//`cd ..; pwd`\/})
line=$(echo ${line/#.\//`pwd`\/})
echo $line

基本的字符串前端替换遵循以下公式 ${/ #子字符串替换字符串} 在这里讨论得很好:https://www.tldp.org/LDP/abs/html/string-manipulation.html

当我们希望/是我们找到/替换的字符串的一部分时,\字符对/求反。

如果相对路径是一个目录路径,那么试试我的,应该是最好的:

absPath=$(pushd ../SOME_RELATIVE_PATH_TO_Directory > /dev/null && pwd && popd > /dev/null)

echo $absPath