Files

如何讓 realpath 永遠不會解析符號連結?

  • April 2, 2020

我正在尋找一個命令來返回文件的絕對路徑,而不解析符號連結。一般來說,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永遠解決符號連結,或者我應該使用另一種方​​法嗎?

程序的目前工作目錄 (CWD) 在作業系統級別從前一個程序繼承,或者可以使用chdir(2). 作業系統(這裡我的意思是“核心”)當然總是會解析任何符號連結以確定最終結果必須是一個目錄,而不是一個符號連結(到一個目錄)。例如,之前的系統呼叫 ( ) 可以在有太多符號連結需要解析時chdir(2)返回錯誤。ELOOP因此,從作業系統的角度來看,CWD 不可能不是任何程序的目錄:作業系統將始終將其解析為真實路徑,而無需任何符號連結。

一旦 shell 完成cd /tmp/test/bar,作業系統將 CWD 路徑解析為/tmp/test/foo. 例如,在 Linux 系統上,ls -l /proc/$$/cwd將顯示核心所見的已解析路徑的連結:/tmp/test/foo.

shell 仍然顯示bar在其提示符中的事實是因為它記住了之前完成的cd命令。行為可能取決於外殼類型。我會在這裡假設 bash 。所以它的內置pwd(但不是外部/bin/pwd命令)、$PWD變數及其在中的使用$PS1將對使用者“撒謊”關於目前目錄。

任何程序,例如realpath,或/bin/pwd從 shell 執行當然都會繼承實際的CWD,即/tmp/test/foo. 所以這不是一個錯誤realpath,它永遠不會有關於bar.

正如 Kusalananda 所建議的那樣,一種可能的尷尬方式是以某種方式重用$PWD變數並將其添加到realpath’s 的論點,前提是它的論點已經不是絕對的。

這是一個例子。我不確定有沒有辦法濫用它。例如,雖然下面的函式可以處理,$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
}

引用自:https://unix.stackexchange.com/questions/577426