1. 程式人生 > >Shell-case:獲取執行的指令碼所在目錄的位置

Shell-case:獲取執行的指令碼所在目錄的位置

     今天和大家分享一個,大家shell指令碼中常常想用,但卻很難完成的一個功能的shell指令碼,如何獲取當前執行shell指令碼所在目錄位置。
     很多時候,我們寫一個shell指令碼在實現一個功能的時候不單單是一個shell指令碼在進行工作,我們可能還有其他的一些檔案輔助進行,而我們分享的時候通常會壓縮到一個包中,而使用者下載後解壓使用,但問題也就出現了,我們並不知道使用者解壓在上面位置,如果用絕對路徑壓縮,會大大降低使用者個性化使用感,這時候我們就希望能執行shell指令碼的時候,shell指令碼能獲取shell指令碼自身所在位置,那如何實現?話不多說,先上程式碼:

  path=${0%/*}
  echo $path | grep '^/' &>/dev/null
  if [ $? -ne 0 ];then
    path=$(echo $path | sed -r 's/.\/*//')
    path=$PWD/$path
  fi
  path=$(echo $path | sed -r 's/\/{2,}/\//')

  echo '指令碼所在位置為'$path

     思考方向和演算法思考差不多,我們從問題著手,如何讓一個shell指令碼執行的時候獲得其具體位置,說到位置,我們第一個想到的系統變數就是$PWD,但是他是獲取使用者當前路徑,和指令碼沒有關係,再想和路徑相關的就是$0,他可以獲取使用者執行指令碼的時候使用的路徑,不過不同的指令碼執行方法其$0的含義都不同,那首先我們就要先弄清楚如何執行一個shell指令碼呢?想執行一個shell指令碼,我們就要知道什麼是shell指令碼,這就涉及到一堆理論了,具體的,大家可以去閱讀我一週的shell指令碼學習blog,下面我就直接來總結一下然後執行shell指令碼,執行的方法大致是這三種

  1. 絕對路徑執行(以當前使用者預設的shell直譯器解釋啟動指令碼)
  2. ./相對路徑的指令碼執行(這實質上也是以絕對路徑執行)
  3. 直譯器   相對路徑 (這是使用者指定直譯器,然後執行指令碼)

     那就分著三種情況進行分析,具體每個方案來做具體的操作,操作前,我們要先想怎麼才能分出使用者用的什麼方法,由上文的分類,我們不難看出,這三個方法中使用者輸入的路徑都是不同的,絕對路徑使用者輸入的一定是 / 開頭,到指令碼目錄執行,使用者一定是輸入的 . 開頭的,而直譯器後面跟著相對路徑一定是 / 開頭或者字母數字,再分析一下,只要使用者輸入的不是以 / 開頭的都是相對目錄,那就好辦了,我們用$0獲取使用者輸入的是什麼,然後用grep判斷一下即可,具體操作如下:

  echo $0 | grep '^/' &>/dev/null
  if [ $? -ne 0 ];then
    echo 使用者輸入的是相對路徑下的指令碼
  else
    echo 使用者輸入的絕對路徑,下的指令碼
  fi

     絕對路徑下的指令碼無所謂,我們直接就可以拿來用,相對路徑,我們把當前使用者所在位置接上就好,那麼就是相對路徑的情況中,我們進行
path=$PWD$0
絕對路徑直接引用
path=$0
     這樣實質上就已經獲取了路徑了,path就可以算是一個完整的指令碼所在的絕對路徑的位置,不過在實際使用中,我們會想要獲取的是指令碼所在目錄的路徑,剛剛獲取的是指令碼所在完整路徑,其中包含了指令碼名,我們想去掉指令碼名,這其實很簡單,把path進行去尾操作即可,可以再開始做分隔前,也可以在分隔後,都一樣,不過如果在執行後進行處理,必須在目錄後加上 / ,防止本來位置就是 / ,進行去尾後什麼都沒有,而執行前處理結果以目錄名結尾,刪除不可能全部刪完,所以大家自行斟酌取捨,具體去尾程式碼如下

path=${0%/*}

     到此為止,基本可以實現所有功能了,不過測試中發現了bug,就是用./執行指令碼的時候,發現目錄中還包含 ./ 這其實很簡單,用sed吧 ./ 全部刪掉即可,這裡用到sed的拓展正則:

path=$(echo $path | sed -r 's/.\/*//')

     最後為了美觀,我們把目錄路徑中全部多個 / 改成一個,這些是美化工作,不做也不會影響正常的使用,具體操作程式碼如下:

path=$(echo $path | sed -r 's/\/{2,}/\//')

     組合起來就得到最終程式碼,程式碼可以直接被套用,需要獲取指令碼所在位置的道友,直接拷貝進自己的指令碼中即可,不過注意不要出現變數名衝突的情況即可。

附:有不足的地方,望各位大佬指出,可以留言也可以email給作者,如果喜歡可以收藏轉發,但請註明出處,謝謝。