Zsh

如何將zsh別名函式傳遞給管道

  • August 17, 2021

我有一個 zsh 別名:

gitbs() {
   git branch | grep -- $1
}

我想將結果傳遞給 git checkout,例如: git checkout | gitbs state 我怎樣才能使它工作?

外殼管道將命令的輸出傳遞到另一個命令的輸入。這在這裡對您沒有幫助:您希望將命令的輸出作為另一個命令的命令行參數傳遞。用於此的工具是命令替換。所以基本思想是

git checkout "$(gitbs state)"

(它仍然是引擎蓋下的管道,但管道的讀取端是外殼本身:它讀取輸出,然後構造一個包含該輸出的命令行。)

但是, 的輸出gitbs state不是傳遞給的正確格式git checkout:它在與分支名稱相同的行上有額外的空格,有時還有標點符號。(還有顏色格式程式碼,但僅當輸出是終端或 git 自動呼叫尋呼機時,而不是當輸出是管道時。)此外,如果沒有匹配的分支或多個分支,你會得到一些來自的奇怪錯誤消息git checkout

要解決此問題,您可以更改gitbs以生成原始分支名稱作為輸出。如果輸出是終端,這是一個保留用於人類的漂亮格式的版本,否則每行只列印一個分支名稱。它用於git for-each-ref列舉分支名稱。條件表達式 -t 1測試標準輸出是否為終端。

gitbs () {
 if [[ -t 1 ]]; then
   git branch
 else
   git for-each-ref --format='%(refname:lstrip=2)' 'refs/heads/*'
 fi | grep -- "$1"
}

有了這個定義gitbs,git checkout "$(gitbs state)"就可以了。

請注意命令替換周圍的雙引號。如果沒有雙引號 ( ),輸出將在空格處拆分為單獨的參數,因此如果多個分支匹配,則git checkout $(gitbs state)生成的命令將類似於存在一個名為的文件。git checkout foobar1 foobar2``foobar1``foobar2``foobar1``foobar2

為了避免這個陷阱,最好定義一個gitbs需要單個匹配分支的不同版本。如果有零個或多個匹配分支,您將受益於更清晰的錯誤消息,儘管仍然有一條關於目前分支的額外消息來自git checkout. 此函式將匹配的分支列表放入數組中

gitbs1 () {
 local branches
 branches=($(git for-each-ref --format='%(refname:lstrip=2)' 'refs/heads/*' | grep "$1"))
 if ((#branches == 0)); then
   echo "No branch contains '$1'" >&2
   return 3
 fi
 if ((#branches > 1)); then
   echo "Multiple branches match '$1':" >&2
   print -lr $branches >&2
   return 3
 fi
 echo $branches
}

然後你就可以放心地寫了git checkout $(gitbs1 state)


如果您打開該選項glob_complete(即setopt glob_complete在您的.zshrc),那麼您可以輸入

git 分支 *foo*Tab

*foo*如果有匹配分支的名稱,則替換為匹配分支的名稱。如果有多個匹配的分支,您將獲得與普通(前綴)補全相同的菜單或循環行為。

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