目前的情况是,我已经定义了一些.zshrc
别名
alias gco='git checkout'
alias cdp='cd ..'
和很多这样的。我的问题是每次输入别名并按 Enter 时如何打印命令?
前任:
$> gco master
> Command: git checkout master
> Git process ...
类似的东西,如果解决方案也适用于 bash 会更好!谢谢!
这是一个巧妙的问题。我们可以通过定义几个函数来扩展别名来做到这一点,然后preexec
在我们执行它们之前使用一个钩子来运行这些函数。
我从这里得到了答案。
_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'
如果输入了别名,我们现在可以检测到它,然后打印它:
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
}
该preexec
功能非常适合这一点。这是一个功能:
在读取命令并即将执行后立即执行。如果历史机制处于活动状态(并且该行没有从历史缓冲区中丢弃),则用户键入的字符串作为第一个参数传递,否则为空字符串。将执行的实际命令(包括扩展别名)以两种不同的形式传递:第二个参数是命令的单行、大小限制版本(省略了函数体之类的内容);第三个参数包含正在执行的全文。
注意,我们可能只使用 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
),不会显示完整的命令。运行别名命令(如1
或rake
)时,将显示完整的命令。
git
运行别名时(例如git lg1
),不会git
扩展别名。如果您查看我的第一个链接,那里的完整示例确实使用git
别名扩展 - 如果 git 别名对您至关重要,您应该接受并修改。