如何使 realpath 永远不会解析符号链接?

如何使 realpath 永远不会解析符号链接?

我正在寻找一个命令来返回文件的绝对路径,而不解析符号链接。一般来说,realpath这方面做得很好。

$ mkdir /tmp/test; cd /tmp/test
$ mkdir foo
$ ln -s foo bar
$ realpath -se bar           # good, this does not resolve the symlink
/tmp/test/bar

它也适用于符号链接目录内的文件。

$ touch foo/file
$ realpath -se bar/file      # good, this does not resolve the symlink
/tmp/test/bar/file

然而,当现任董事符号链接目录

$ cd bar
$ pwd
/tmp/test/bar
$ realpath -se file          # this fails, returning the target
/tmp/test/foo/file
$ realpath -se .             # this also fails, returning the target
/tmp/test/foo
$ realpath -se /tmp/test/bar/file # yet this works
/tmp/test/bar/file
$ realpath -se /tmp/test/bar # and this works
/tmp/test/bar

为什么会有realpath这样的行为? (这是一个错误吗?)有没有办法realpath永远不解析符号链接,或者我应该使用其他方法吗?

答案1

进程的当前工作目录 (CWD) 在操作系统级别从前一个进程继承,或者可以使用chdir(2).操作系统(这里我的意思是“内核”)当然将始终解析任何符号链接以确定最终结果,该结果必须是目录,而不是符号链接(到目录)。例如,当有太多符号链接需要解析时,前面的系统调用 ( chdir(2)) 可能会返回错误。ELOOP因此,从操作系统的角度来看,不可能存在 CWD 不是任何进程的目录:操作系统将始终将其解析为真实路径,而在任何地方都没有任何符号链接。

一旦 shell 完成cd /tmp/test/bar,CWD 路径就会被操作系统解析为/tmp/test/foo.例如,在 Linux 系统上,ls -l /proc/$$/cwd将显示内核所看到的已解析路径的链接:/tmp/test/foo

barshell 仍然显示在提示符中的事实是因为它记住了光盘之前完成的命令。该行为可能取决于 shell 类型。我假设这里有 bash。因此,它是内置的pwd(但不是外部/bin/pwd命令),$PWD变量及其使用$PS1将向用户“撒谎”有关当前目录的信息。

任何进程,例如realpath/bin/pwd从 shell 运行的进程当然都会继承实际的CWD,即/tmp/test/foo.所以这不是 中的错误realpath,它永远不会有关于 的具体信息bar

正如 Kusalananda 所建议的,一种可能的尴尬方法是以某种方式重用该变量,并仅在其参数不是绝对的情况下$PWD将其添加到 的参数之前。realpath

这是一个例子。我不确定是否有办法滥用它。例如,虽然下面的函数可以应付,$PWD但变量本身在 bash 4.4.12 (Debian 9) 中表现不佳,但如果路径中有换行符,则在 bash 5.0.3 (Debian 10) 中工作正常。当某处有换行符时,为了有用,-z还应该添加一个选项realpath,但我不会在这个简单的示例中重新实现选项的整个解析。

myrealpathnofollowsym () {
    for p in "$@"; do
        if ! printf '%s' "$p" | grep -q -- '^/'; then
            realpath -se "$PWD/$p"
        else
            realpath -se "$p"
        fi
    done
}

相关内容