Shell
為什麼命令中的星號導致 for 循環正在擴展?
我想編寫一個可以執行的腳本
git diff --name-status master..<BRANCH>
但是當我執行這個時:
for i in $(git branch | grep -v master); do echo $i; done
我得到回顯一個目錄,因為
git branch
回顯星號(我在目前目錄中有一個目錄)* <SELECTED BRANCH>
為什麼
*
要擴展,如何防止擴展?更新:我可以通過使用這個來防止這種情況:
for i in $(git branch | tr -d '*' | grep -v master); done;
但是為什麼會這樣呢?為什麼我需要刪除星號?
不帶引號的變數和命令替換類似於
$i
或$(git …)
將split+glob 運算符應用於字元串結果。那是:
- 建構一個包含變數值或命令輸出的字元串(在後一種情況下減去最後的換行符)。
- 根據 的值將字元串拆分為單獨的欄位
IFS
。- 將每個欄位解釋為萬用字元模式,並將其替換為匹配的文件名列表;如果模式與任何文件都不匹配,請保持原樣。
(第 1 步)的輸出
git branch | grep -v master
包含* master
將(第 2 步)拆分為兩個欄位*
和master
;*
被目前目錄中的文件名列表替換(步驟 3)。您可以執行
set -f
以暫時禁用萬用字元。另一種方法是避免命令替換,而是使用read
. 但是,兩者都不做正確的事情——你會有虛假的分支名稱,因為 git 輸出包含的內容超出了你的需要(*
指示目前分支的標誌,還有remotes/somewhere/foo -> bar
遠端跟踪分支之類的東西)。如果不優雅,我認為以下內容是安全的:for i in $(git branch | sed -e 's/^..//' -e 's/ .*//'); do echo $i done
我認為穩健的方法是使用
git-for-each-ref
.for i in $(git for-each-ref --format='%(refname:short)' refs/heads refs/remotes); do echo $i done