git - 是否可以在 Git 中对 shell 的内置命令使用别名扩展?

标签 git shell alias

我的 .gitconfig 中有以下别名:

freq = !history | cut -c 8- | grep ^git | sort | uniq -c | sort -n -r | head -n 5

它应该显示我最常使用的 5 个 git 命令。取自此处:http://alblue.bandlem.com/2011/04/git-tip-of-week-aliases.html (我知道这篇文章是旧的)

当我运行命令时,它没有输出任何内容:

$ git freq
$

但是如果我运行 history |切-c 8- | grep ^git |排序 | uniq-c |排序-n -r | head -n 5,给出输出:

$ history | cut -c 8- | grep ^git | sort | uniq -c | sort -n -r | head -n
   5 git log
   5 git status
   5 git current
   5 git co master
   4 git co other-branch

我猜这是因为 history 是一个 shell 内置命令,如果我更改 freq 别名,例如到:

freq = !history

我得到:

$ git freq
error: cannot run history: No such file or directory
fatal: While expanding alias 'freq': 'history': No such file or directory
$

有没有办法让它发挥作用?

最佳答案

原因

看完问题后,我也认为问题是由于 history 是一个 shell builtin。

调试 git

Git命令可以通过设置GIT_TRACE环境变量来调试 为 true(有关更多信息,请参阅 Scott Chacon 的 Git 书中有关 Git Internals - Environment Variables 的相关部分)。

$ GIT_TRACE=true git freq

10:14:11.901296 git.c:554               trace: exec: 'git-freq'
10:14:11.901296 run-command.c:341       trace: run_command: 'git-freq'
10:14:11.932496 run-command.c:341       trace: run_command: 'history | tail'
10:14:11.963697 run-command.c:192       trace: exec: '/bin/sh' '-c' 'history | tail' 'history | tail'

Checking the source显示外部命令由调用 sane_execvpexecv_shell_cmd 函数处理,这是一个对 execvp 标准更友好的前端library 函数,如果命令名称不包含斜杠,则在 PATH 中的每个目录中搜索与命令同名的可执行文件。由于 history 是一个内置的 shell,它永远不会被发现,所以它会返回一个错误。见


我不是一个听之任之的人,后来我使用其他 shell 内置插件进行了进一步的实验,这些实验成功了,所以我认为它一定是别的东西:

没有非交互式 shell 的历史记录

阅读 Bash 手册解释了 Bash History Facilities仅用于 interactive shells而由 exec 调用启动的 shell 是非交互式的。这就是为什么运行 history 内置函数不打印任何输出的原因。


解决方案

选项 1:在非交互式 shell 中打开历史记录功能

感谢Gilles on Unix and Linux ,事实证明,可以通过设置 HISTFILE shell 变量然后运行 ​​set -o history 来打开非交互式 shell 中的历史功能,如下所示运行:

bash -c "HISTFILE=~/.bash_history; set -o history; history"

.gitconfig 中设置以下别名将起作用:

freq = "!HISTFILE=$HOME/.bash_history; set -o history; history | cut -c 8- | grep ^git | sort | uniq -c | sort -n -r | head -n 5"

注意:如果您使用的是 Bash 以外的 shell,则需要指定 shell 将其命令历史记录保存到的文件的名称。如果您使用的是 Bash,则 HISTFILE shell 变量可能设置为 $HOME/.bash_history 以外的值。

此外,诸如 HISTFILE 之类的 shell 变量不应作为环境变量导出(可用于 git),这就是我在这里没有使用它的原因。

选项2:从历史文件中读取

一个更简单的解决方案是直接从 shell 历史文件中读取:

freq = !grep ^git $HOME/.bash_history | sort | uniq -c | sort -n -r | head -n 5

这将产生与在新的交互式 shell 中运行 history 命令相同的结果,因为当新的 shell 启动时,除了从历史文件中读取的内容外,它的历史记录中没有任何命令.

此外,直接从历史文件中读取时不需要cut命令。

选项 3:Bash 别名

另一种选择是忘记使用 Git 别名而只使用 Bash 别名:

alias git-freq='history | cut -c 8- | grep ^git | sort | uniq -c | sort -n -r | head -n

保持 shell 历史文件是最新的

我想我应该添加以下有用的辅助信息。请注意,它适用于交互式 Bash shell,它可能适用于也可能不适用于其他现代 shell。

我经常在同一台主机上同时运行多个 shell,并且我不希望在退出 shell 时覆盖保存的历史命令。这是我的 .bashrc 设置,可确保在每个命令后写入 shell 历史文件:

# Append history entries on logout - instead of over-writing the history file.
shopt -s histappend

# Don't store duplicate lines in the history.
# Ignore any commands that begin with a space.
HISTCONTROL=ignoredups:ignorespace

# Use a very large history file to store lots of commands.
# See http://mywiki.wooledge.org/BashFAQ/088
HISTFILESIZE=5000
# Keeping a large history requires system resources
HISTSIZE=3000

# Append to the history file after every command.
PROMPT_COMMAND="history -a"

关于git - 是否可以在 Git 中对 shell 的内置命令使用别名扩展?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32625352/

相关文章:

ruby-on-rails - 从另一个本地分支推送到 heroku

bash - 编写启动 ncmpcpp 的 3 个 Pane 的功能性 tmux shell 脚本是不可能的吗?

linux - 读取 shell 脚本时如何处理未找到的文件

c - memcpy 和 "alias"的奇怪行为

database - 如何在 PostgreSQL 中定义运算符别名?

git - 我从哪里分支?

linux - 如何在我的 bash PROMPT 中为当前的 git 分支添加颜色?

Java Runtime.exec() 不支持 Linux 别名

Git:如何列出带有跟踪远程信息的分支?

linux - Shell,For循环进入目录和子目录未按预期工作