Bash

更改到呼叫腳本的目錄的最安全(或最優雅或最短)的方法是什麼?

  • March 8, 2016

我想知道什麼可能是安全或與 Unix 兼容的方式來更改到呼叫腳本的目錄。

這兩種方法甚至可以在包含空格和特殊字元的目錄中使用,而無需使用引號。但在某些情況下,這可能不起作用。或者有嗎?

#!/bin/bash

cd $(dirname $0)
pwd
cd ${0%/*}
pwd

~/test 1"\ ü`\($$ ./cd.sh
/home/syss/test 1"\ ü`\($
/home/syss/test 1"\ ü`\($

請注意,這$0可能是相對路徑,因此呼叫cd兩次可能不起作用。除此之外,在大多數情況下,提取目錄部分的$0工作。大多數不一樣*。*它可能失敗的一些情況包括:

  • 腳本不是通過執行它的路徑來呼叫的,而是通過呼叫它的shell來呼叫的,例如bash myscript(它進行PATH查找)。
  • 腳本在執行期間被移動。

只要您記錄必須在沒有惡作劇的情況下呼叫您的腳本,就可以使用目錄部分$0

你需要小心一點;如果它$0是通過一個空條目找到的,或者PATH對於某些 shell,它是一個. 這個案例值得支持,也意味著你需要採取預防措施。PATH``.``${0%/*}

這種dirname方法也不是完全簡單的。命令替換在最後吃掉了換行符。對於這兩種方法,您需要注意字元串可以以選項開頭-並被解釋為選項;傳遞--終止命令的選項列表。

case "$0" in
 */*) cd -- "${0%/*}";;
 *) cd -- "$0";;
esac

或者

cd -- "$(dirname -- "$0"; echo /)"

關於雙引號,您問錯了問題。"$0"是參數的值0$0,未加引號的,是參數的值,0在每個元素的字元處拆分,IFS然後解釋為全域模式,如果有任何匹配文件,則替換為匹配文件(只有在未關閉通配的情況下才會替換後一部分)。您並不是說參數的值0在每個元素中的字元處拆分,IFS然後解釋為全域模式並替換為匹配文件(如果有的話)(只有在沒有關閉全域的情況下),是嗎?你的意思是參數的值0。所以寫下你的意思:"$0"

您的測試沒有阻塞的唯一原因是您沒有嘗試使用有問題的名稱,並且您使用特定的外殼進行了測試,該外殼恰好可以在這種特定情況下修復您的錯誤。使用類似 的目錄名稱foo bar,您最終會傳遞兩個參數foobarcd命令;bash 的cd命令將此解釋為“更改通過連接foo、空格和獲得的目錄bar”,因此它恰好重建了正確的名稱。不同的 shell 可能會將其解釋為“抱怨虛假參數”、“更改目錄”或“更改為在目前工作目錄中foo通過替換獲得的foo目錄”。bar例如,使用 bash,如果名稱包含兩個連續的空格,您的腳本就會失敗。

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