Bash:检索给定相对的绝对路径

nub*_*bme 135 bash shell path absolute

是否有命令在给定相对路径的情况下检索绝对路径?

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

find ./ -type f | while read line; do
   echo $line
done
Run Code Online (Sandbox Code Playgroud)

epe*_*re4 149

试试realpath.

~ $ sudo apt-get install realpath  # may already be installed
~ $ realpath .bashrc
/home/username/.bashrc
Run Code Online (Sandbox Code Playgroud)

要避免扩展符号链接,请使用realpath -s.

答案来自" bash/fish命令打印文件的绝对路径 ".

  • Mac上似乎没有`realpath`(OS X 10.11"El Capitan").:-( (9认同)
  • 在osx上,`brew install coreutils`将引入`realpath` (6认同)
  • 令人惊讶的是,“realpath”在 Windows 版 Git 上可用(至少对我来说)。 (2认同)

Mor*_*kus 96

如果您安装了coreutils软件包,通常可以使用readlink -f relative_file_name它来检索绝对软件包(已解决所有符号链接)

  • 不幸的是,这不适用于Mac :( (17认同)
  • 此行为与用户要求的行为略有不同,它还将遵循并解决路径中任何位置的递归符号链接.在某些情况下,您可能不希望这样. (2认同)
  • @BradPeabody 如果您从自制软件 `brew install coreutils` 安装 coreutils,这在 Mac 上确实有效。然而,可执行文件前面带有 ag: `greadlink -frelative_file_name` (2认同)
  • 请注意,readlink(1)的手册页具有其描述的第一句:"注意realpath(1)是用于规范化功能的首选命令." (2认同)

mpa*_*pis 57

使用:

find $(pwd)/ -type f
Run Code Online (Sandbox Code Playgroud)

获取所有文件或

echo $(pwd)/$line
Run Code Online (Sandbox Code Playgroud)

显示完整路径(如果相对路径很重要)

  • 然后看到评论链接到你的问题,最好的方法可能是'readlink -f $ line' (11认同)
  • 为什么用$(pwd)代替$ PWD?(是的,我知道`pwd`是内置的) (3认同)
  • 如果我在查找中指定相对路径该怎么办? (2认同)

Eug*_*kov 56

#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
Run Code Online (Sandbox Code Playgroud)

UPD一些解释

  1. 此脚本将相对路径作为参数 "$1"
  2. 然后我们得到该路径的dirname部分(您可以将dir或文件传递给此脚本):dirname "$1"
  3. 然后我们cd "$(dirname "$1")进入这个相对目录并通过运行pwdshell命令获取它的绝对路径
  4. 之后,我们将basename附加到绝对路径:$(basename "$1")
  5. 作为最后一步,我们echo

  • 这个答案使用了最好的Bash成语 (8认同)
  • 我喜欢答案,但是只有在允许用户将CD插入目录的情况下,它才有效。这可能并不总是可能的。 (3认同)
  • 我个人最喜欢的:)不幸的是,当我喂它“”时,它失败了。和“..”作为相对路径。略有改进的版本:/sf/answers/3588495571/ (3认同)
  • readlink是适用于Linux的简单解决方案,但该解决方案也适用于OSX,因此+1 (2认同)
  • @josch:问题不在于符号链接解析。但是,如果要这样做,可以在`pwd`命令中提供`-P`选项:`echo“ $(cd” $(dirname“ $ 1”)“; pwd -P)/ $(basename” $ 1“)” ` (2认同)
  • 对于已经是绝对路径的路径无法正常工作。 (2认同)

syn*_*tel 31

为了它的价值,我投票选出了答案,但想分享一个解决方案.不足之处是,它仅仅是Linux的 - 我花了约5分钟,试图找到OSX等价来栈溢出了.我确定它在那里.

在Linux上,您可以readlink -e与之配合使用dirname.

$(dirname $(readlink -e ../../../../etc/passwd))
Run Code Online (Sandbox Code Playgroud)

产量

/etc/
Run Code Online (Sandbox Code Playgroud)

然后你用dirname姊妹basename来获取文件名

$(basename ../../../../../passwd)
Run Code Online (Sandbox Code Playgroud)

产量

passwd
Run Code Online (Sandbox Code Playgroud)

把它们放在一起..

F=../../../../../etc/passwd
echo "$(dirname $(readlink -e $F))/$(basename $F)"
Run Code Online (Sandbox Code Playgroud)

产量

/etc/passwd
Run Code Online (Sandbox Code Playgroud)

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

  • 只是readlink -e ../../../../etc/passwd在这里工作 (3认同)

Ern*_*t A 24

我认为这是最便携的:

abspath() {                                               
    cd "$(dirname "$1")"
    printf "%s/%s\n" "$(pwd)" "$(basename "$1")"
    cd "$OLDPWD"
}
Run Code Online (Sandbox Code Playgroud)

如果路径不存在,它将失败.

  • 没有必要再次回来.请参见http://stackoverflow.com/a/21188136/1504556.你的本页是恕我直言的最佳答案.对于那些感兴趣的人,链接给出了*为什么*这个解决方案有效的解释. (3认同)

bab*_*bou 16

realpath 可能是最好的

但......

最初的问题一开始就很困惑,其中一个例子与所陈述的问题关系不大.

所选答案实际上回答了给出的示例,而不是标题中的所有问题.第一个命令是答案(真的吗?我怀疑),并且没有'/'也可以.我没有看到第二个命令正在做什么.

有几个问题好坏参半:

  • 将相对路径名更改为绝对路径名,无论它表示什么,可能都没有.(通常,如果发出诸如此类的命令touch foo/bar,则foo/bar在实际创建文件之前,路径名必须存在,并且可能在计算中使用.)

  • 可能有几个绝对路径名表示相同的文件(或潜在文件),特别是因为路径上的符号链接(符号链接),但可能出于其他原因(设备可能以只读方式挂载两次).可能会或可能不想解决明确的这种符号链接.

  • 到达非符号链接文件或名称的符号链接的末尾.这可能会也可能不会产生绝对路径名,具体取决于它是如何完成的.并且可能或可能不想将其解析为绝对路径名.

readlink foo没有选项的命令仅在其参数foo是符号链接时给出答案,并且该答案是该符号链接的值.没有其他链接.答案可能是一个相对路径:symlink参数的值是什么.

但是,readlink具有适用于所有文件的选项(-f -e或-m),并为参数实际表示的文件提供一个绝对路径名(没有符号链接的路径名).

这适用于任何非符号链接的东西,但有人可能希望使用绝对路径名而不解析路径上的中间符号链接.这是由命令完成的realpath -s foo

对于符号链接参数,readlink其选项将再次解析参数的绝对路径上的所有符号链接,但这也将包括遵循参数值可能遇到的所有符号链接.如果你想要一个参数符号链接本身的绝对路径,而不是它可能链接到的任何东西,你可能不希望这样.同样,如果foo是符号链接,realpath -s foo将获得绝对路径而不解析符号链接,包括作为参数给出的符号链接.

如果没有-s选择,realpath确实几乎一样 readlink,除了简单的阅读环节的价值,以及其他一些事情.我不清楚为什么readlink有它的选择,显然是一个不合需要的冗余 realpath.

除了跨系统可能存在一些变化之外,探索网络并没有多说什么.

结论:realpath最好的命令是使用,具有最大的灵活性,至少在这里要求使用.


bio*_*ker 7

欧根的答案对我来说并不适用,但这样做了:

    absolute="$(cd $(dirname \"$file\"); pwd)/$(basename \"$file\")"
Run Code Online (Sandbox Code Playgroud)

旁注,您当前的工作目录不受影响.


has*_*nge 7

我最喜欢的解决方案是一个由@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
}
Run Code Online (Sandbox Code Playgroud)


MrS*_*lty 5

最好的解决方案,恕我直言,是在这里发布的:https : //stackoverflow.com/a/3373298/9724628

它确实需要 python 才能工作,但它似乎涵盖了所有或大部分的边缘情况,并且是非常便携的解决方案。

  1. 通过解析符号链接:
python -c "import os,sys; print(os.path.realpath(sys.argv[1]))" path/to/file
Run Code Online (Sandbox Code Playgroud)
  1. 或没有它:
python -c "import os,sys; print(os.path.abspath(sys.argv[1]))" path/to/file
Run Code Online (Sandbox Code Playgroud)