
我正在尋找一個命令來返回文件的絕對路徑,而不解析符號連結。一般來說,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
。
bar
shell 仍然顯示在提示符號中的事實是因為它記住了光碟之前完成的命令。該行為可能取決於 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
}