可靠地辨識包含執行腳本的目錄的路徑
SO中有很多答案可以解決這個問題:
對於原始碼腳本,Unix 和 Linux 中也有一些類似的問題。
不過,其中一些是特定於 Bash 的(它們依賴於
$BASH_SOURCE
)。如果目錄名稱包含換行符,其中一些不起作用,如果涉及符號連結,其中一些不起作用。在每個主要 shell 中獲取包含執行/呼叫腳本的目錄的路徑的可靠方法是什麼?有一個檢查每種外殼類型的解決方案很好。
有一些啟發式方法可以幫助您,但沒有完全可靠的方法。
Otheus 展示瞭如何使用文件描述符。這是一個很好的啟發式方法,在大多數情況下都有效。但是,在某些極端情況下它會失敗,並且無法檢測到失敗。
範例:採用以下腳本。
#!/bin/sh set lsof -p$$ | sed 's/[0-9][0-9]*//'
製作兩份腳本副本,一份名為
foo
,一份名為bar
。現在讓我們稍微強調一下:$ env -i PATH=/bin:/usr/bin perl -MPOSIX -e 'dup2(4, 11) or die $!; exec "dash", "foo", "bar"' 3<foo 4<bar </dev/null >foo.out $ env -i PATH=/bin:/usr/bin perl -MPOSIX -e 'dup2(3, 10) or die $!; exec "dash", "bar", "foo"' 3<foo 4<bar </dev/null >bar.out $ diff foo.out bar.out
17c17 < dash gilles 1w REG 0,24 99 10130024 /tmp/202954/foo.out —
dash gilles 1w REG 0,24 99 10130022 /tmp/202954/bar.out
這裡唯一的區別是我記錄輸出的文件。
這種啟發式方法會失敗的另一種情況是,如果 shell 是在標準輸入上呼叫的,或者使用
-c
.另一種方法是解析 shell 的命令行。在 Linux 上,您可以通過
/proc
. 參數是空分隔的,很難用可移植的 shell 工具解析(最近的 GNU 工具使它更容易),但可以做到。可移植地,您需要呼叫ps
來訪問參數,並且沒有明確的輸出格式:ps -o args
將參數與空格連接起來,並且可能會被截斷。即使在 Linux 上,您在這裡遇到的問題是 shell 可能已使用您的腳本不知道的選項呼叫,並且其中一個選項可能帶有參數。例如,假設您有一個名為的腳本
1
和另一個名為2
.mksh -T 1 2
這將呼叫 mksh on
/dev/tty1
並執行腳本2
。zsh -T 1 2
這使用選項呼叫 zsh 並使用參數
cprecedences
執行腳本。1``2
您需要了解各個外殼的知識才能將它們區分開來。使用此方法,您可以檢測邊緣情況:如果您看到非標準選項,請退出。
我將對此進行第一階段的嘗試。希望其他人會有所改善。
在執行腳本之前,shell 將打開文件的文件描述符。通常這是在 fd 255 分配的。無論如何,如果有一個 open
fd
,那麼lsof
可以找到它。所以我們使用lsof -p $$
並獲得最高文件描述符的文件名。lsof
不適用於所有類型的 Unix。BSD 的 wiki 說有fstat
. 它似乎在達爾文(Mac OS)上。用`-F範例腳本:
#!/bin/sh this_script_path=`lsof -p $$ | awk '/\/'${0##*/}'$/' | cut -c 55-`
顯然,切割非常依賴於 lsof 的特定格式。我們可以在版本 2 中緩解這種情況。順便說一句:我的版本會
lsof
翻譯不可列印的字元,這樣即使路徑名中的製表符也會轉換為\t
.第 2 版。為醜陋的 perl 程式碼提前道歉。這次我們將使用
-F
選項來控制輸出。-F fn
我們將得到如下輸出:p3834 fcwd n/home/joe/test frtd n/ ftxt n/bin/bash fmem n/lib64/ld-2.12.so fmem n/lib64/libdl-2.12.so fmem n/lib64/libc-2.12.so fmem n/lib64/libtinfo.so.5.7 fmem n/usr/lib/locale/locale-archive fmem n/usr/lib64/gconv/gconv-modules.cache f0 n/dev/pts/1 f1 n/dev/pts/1 f2 n/dev/pts/1 f255 n/home/joe/test/t.sh
我們必須轉換那個混亂,以便最高的文件描述符(我假設你不能依賴它是 255)是腳本名稱。(這似乎
dash
也有效。)this_script_path=`lsof -p $$ -F fn | perl -lane ' $fd=$1,next if /^f(\d+)/; $p{$fd}=$1 if $fd and /^n(.*)/; $fd=""; }END { @x=sort {$a<=>$b} keys %p; print $p{$x[-1]}; }{'`
perl 腳本很醜,我同意。為了清楚起見,我把它分開了。如果行以 開頭
f
,我們擷取文件描述符的編號,如果我們有有效的文件描述符和有效的文件名,我們將文件名擷取到散列中。以防萬一,如果這些條件都不滿足,我們清除$fd
. 在處理完所有行之後,我們對雜湊的鍵(我們的文件描述符)進行數字排序,將結果儲存到數組x
中並輸出p
文件名雜湊的內容,由數組中的最後一個元素(最大值)索引x
。唯一的問題是:是否會在所有系統上安裝 lsof 以及這種輸出格式的穩定性如何。