在zsh或bash中打印已执行的别名

15

目前的情况是,我在.zshrc中定义了一些别名,比如:

alias gco='git checkout'
alias cdp='cd ..'

还有很多类似的东西。我的问题是如何在我键入别名并按下回车时每次打印出该命令?

例如:

$> gco master
> Command: git checkout master
> Git process ...

如果这个解决方案也能在Bash中运行,那就更好了!谢谢!


这是一个接近重复的 https://dev59.com/XWDVa4cB1Zd3GeqPdnms。 - Jon Schneider
在zsh中,只需键入“..”,它就像“cd ..”一样工作。实际上,它适用于任何目录路径,而不仅仅是“..”。(或者也许这种行为是特定于我的配置的) - Lucas Alonso
1个回答

17

这是一个不错的问题。我们可以通过定义几个函数来扩展别名,然后使用 preexec 钩子在执行之前运行这些函数。

我从这里获取了答案。


1. 评估所有别名

_aliases="$(alias -Lr 2>/dev/null || alias)"

alias_for() {
  [[ $1 =~ '[[:punct:]]' ]] && return
  local found="$( echo "$_aliases" | sed -nE "/^alias ${1}='?(.+)/s//\\1/p" )"
  [[ -n $found ]] && echo "${found%\'}"
}

首先,将所有的别名存储在一个变量中。alias -r打印所有的常规别名(不是全局或后缀),而alias -L以“适合在启动脚本中使用的方式”打印它们。 alias_for()函数做了一些清理工作,删除引号并将alias放在行的前面。当我们执行echo ${_aliases}时,会得到类似于以下内容:

alias history='fc -l 1'
alias ls='ls -F -G'
alias lsdf='ls -1l ~/.*(@)'
alias mv='mv -v'

将此与 alias 的输出进行比较:

history='fc -l 1'
ls='ls -F -G'
lsdf='ls -1l ~/.*(@)'
mv='mv -v'

2. 检查是否输入了别名的函数。

如果输入了别名,我们现在可以检测到并打印出来:

expand_command_line() {
  [[ $# -eq 0 ]] && return         # If there's no input, return. Else... 
  local found_alias="$(alias_for $1)"    # Check if there's an alias for the comand.
  if [[ -n $found_alias ]]; then         # If there was
    echo ${found_alias}                  # Print it. 
  fi
}

3. 让程序在每次输入命令时都运行

preexec函数非常适合这个任务。它是一个函数,会在以下情况下被执行:

在读取并即将执行一条命令后执行。如果历史机制处于活动状态(并且该行未从历史缓冲区中舍弃),则用户键入的字符串将作为第一个参数传递,否则它是一个空字符串。将要被执行的实际命令(包括扩展的别名)以两种不同的形式传递:第二个参数是一个单行、大小限制版本的命令(类似于省略了函数体的东西);第三个参数包含正在执行的完整文本。

引自zsh手册的第9章

请注意,我们可以使用preeexec函数来显示正在运行的命令信息。

为了将我们的函数添加到preexec中,我们使用此示例中的钩子进行操作。

autoload -U add-zsh-hook        # Load the zsh hook module. 
add-zsh-hook preexec expand_command_line      # Adds the hook 

稍后要移除钩子时,可以使用:

# add-zsh-hook -d preexec expand_command_line # Remove it for this hook.

我的Shell

当我运行它时,这是我的Shell的样子:

$ 1
cd -
$ rake
bundle exec rake
^C
$ chmod
usage:  chmod [-fhv] [-R [-H | -L | -P]] [-a | +a | =a  [i][# [ n]]] mode|entry file ...
    chmod [-fhv] [-R [-H | -L | -P]] [-E | -C | -N | -i | -I] file ...
$ git lg1
fatal: Not a git repository (or any of the parent directories): .git

错误(或“特性”)

从我的shell示例中可以看出,运行未别名化的命令(如chmod)时,并不会显示完整命令。但是当运行别名命令(如1rake)时,将显示完整命令。

当运行git别名命令(例如git lg1)时,不会展开git别名。如果您查看我的第一个链接,那里的完整示例确实使用了git别名展开-如果git别名对您至关重要,则应采用该示例并进行修改。


3
这个答案无与伦比,是 Stack Overflow 上最好的答案之一。 - Eric Jiang
很高兴能找到这样的答案!做得非常好! - equiman
我刚刚发现了这个别名alias obp="explorer.exe \".\\build\""存在一个错误。它运行得很好,但是在控制台中显示的命令是eplorer.exe "uild",路径上缺少.\\ - equiman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接