如何將zsh別名函式傳遞給管道
我有一個 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*
如果有匹配分支的名稱,則替換為匹配分支的名稱。如果有多個匹配的分支,您將獲得與普通(前綴)補全相同的菜單或循環行為。