Shell

shellcheck 建議不要使用 basename:為什麼?

  • January 26, 2020

我正在嘗試shellcheck

我有類似的東西

basename "${OPENSSL}" 

我得到以下建議

Use parameter expansion instead, such as ${var##*/}.

從實際的角度來看,我認為沒有區別

$ export OPENSSL=/opt/local/bin/openssl
$ basename ${OPENSSL}
openssl
$ echo ${OPENSSL##*/}
openssl

由於basenamePOSIX 規範中,我不認為它應該是最佳實踐。有什麼提示嗎?

這與效率無關——它與正確性有關。basename使用換行符來分隔它列印出來的文件名。在通常情況下,當您只傳遞一個文件名時,它會在其輸出中添加一個尾隨換行符。由於文件名本身可能包含換行符,因此很難正確處理這些文件名。

人們通常這樣使用的事實使情況變得更加複雜basename"$(basename "$file")". $(command)這使事情變得更加困難,因為從command. $file考慮以換行符結尾的不太可能的情況。然後basename將添加一個額外的換行符,但"$(basename "$file")"會去掉兩個換行符,給你留下一個不正確的文件名。

另一個問題basename是,如果$file-(破折號又名減號)開頭,它將被解釋為一個選項。這個很容易修復:$(basename -- "$file")

穩健的使用方式basename是這樣的:

# A file with three trailing newlines.
file=$'/tmp/evil\n\n\n'

# Add an 'x' so we can tell where $file's newlines end and basename's begin.
file_x="$(basename -- "$file"; printf x)"

# Strip off two trailing characters: the 'x' added by us and the newline added by basename. 
base="${file_x%??}"

另一種方法是使用${file##*/},它更容易但有其自身的錯誤。特別是在$fileis/或的情況下是錯誤的foo/

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