13

目前的情况是,我已经定义了一些.zshrc别名

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

和很多这样的。我的问题是每次输入别名并按 Enter 时如何打印命令?

前任:

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

类似的东西,如果解决方案也适用于 bash 会更好!谢谢!

4

1 回答 1

14

这是一个巧妙的问题。我们可以通过定义几个函数来扩展别名来做到这一点,然后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打印所有regular别名(不是全局或后缀),并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 时的样子:

$ 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 别名对您至关重要,您应该接受并修改。

于 2013-08-22T02:45:28.593 回答