我有一个 zsh 别名:
gitbs() {
git branch | grep -- $1
}
我想将结果传递到 git checkout 中,例如:
git checkout | gitbs state
我怎样才能使这个工作?
答案1
shell 管道将一个命令的输出传递到另一个命令的输入。这在这里对您没有帮助:您想要将命令的输出作为另一个命令的命令行参数传递。这样做的工具是命令替换。所以基本的想法是
git checkout "$(gitbs state)"
(它仍然是一个管道,但管道的读取端是 shell 本身:它读取输出,然后构造一个包含该输出的命令行。)
但是, 的输出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
,它不会签出,而是会使用if中的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*
如果有的话,将被替换为匹配分支的名称。如果有多个匹配分支,您将获得与普通(前缀)完成相同类型的菜单或循环行为。
答案2
这不是别名,这是一个函数。
如果您想将命令输出中的单词作为参数传递给另一个命令,这就是命令替换的用途:
git checkout $(gitbs state)
将捕获 的输出gitbs state
(这里,无论是函数、别名还是外部命令都无关紧要),删除尾随的换行符,分割 的字符,$IFS
并将生成的单词作为单独的参数传递给git checkout
¹
仅传递该拆分结果的第一个单词:
git checkout ${$(gitbs state)[1]}
将整个输出(减去尾随换行符)传递为一的参数git checkout
,引用它:
git checkout "$(gitbs state)"
要按任意字符串而不是$IFS
字符进行拆分,请使用s
参数扩展标志(或f
按换行符进行拆分):
git checkout ${(f)"$(gitbs state)"}
(请注意,空元素将被删除)。
该xargs
命令可用于此目的,但请注意,拆分是以xargs
非常特殊的方式完成的,并且xargs
只能运行外部命令(不是 shell 内置命令或函数)。
gitbs state | xargs git checkout
xargs
如果输出大量单词(超过一个命令行的容纳范围),则可能会运行git checkout
多次。gitbs state
1 在其他类似 Bourne 的 shell 中,您需要禁用通配符 ( set -o noglob
) 以防止对结果单词执行该操作。这不适用于zsh
除非处于 sh/ksh 模拟模式