Shell

為什麼命令中的星號導致 for 循環正在擴展?

  • August 20, 2014

我想編寫一個可以執行的腳本

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 運算符應用於字元串結果。那是:

  1. 建構一個包含變數值或命令輸出的字元串(在後一種情況下減去最後的換行符)。
  2. 根據 的值將字元串拆分為單獨的欄位IFS
  3. 將每個欄位解釋為萬用字元模式,並將其替換為匹配的文件名列表;如果模式與任何文件都不匹配,請保持原樣。

(第 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

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