解析 zsh 命令行中的所有别名

解析 zsh 命令行中的所有别名

我有嵌套别名,我想在执行命令之前解析所有别名。我怎么做?

如果有一个功能没有绑定到任何键,那么M-x foobar对我来说也很好。我什至可以使用外部命令(、、、type等等)。我尝试了线程中的所有内容commandwhich为什么不用“哪个”呢?那该用什么呢?但没有任何作用。

答案1

请注意,Ctrl-Alt-Ebash不仅可以扩展别名。它还扩展变量、命令替换 (!)、进程替换 (!)、算术扩展和删除引号(它不执行文件名生成(通配符)或波形符扩展)。

它并不总是能够扩展别名。因此,虽然它有其用途,但重要的是要认识到它的结果可能会改变命令行的含义、具有副作用并且具有潜在危险。

例如在:

$ a=';w' b=1
$ alias foo=bar
$ b=2; echo $b $a; cd /tmp/dir && for i do foo $(pwd) <(ls); done

如果我按M-C-E这里,就会出现:

$ b=2; echo 1 ;w; cd /tmp/dir && for i do foo / /dev/fd/63; done

rm -rf *这给了我一个完全不同的命令行(想象一下如果我使用而不是上面的命令行会发生什么pwd)并且不会扩展foo别名。

使用zsh,以 Gilles 关于函数内部扩展的别名的注释为基础,您可以执行以下操作:

expand-aliases() {
  unset 'functions[_expand-aliases]'
  functions[_expand-aliases]=$BUFFER
  (($+functions[_expand-aliases])) &&
    BUFFER=${functions[_expand-aliases]#$'\t'} &&
    CURSOR=$#BUFFER
}

zle -N expand-aliases
bindkey '\e^E' expand-aliases

仅当当前命令行在语法上有效时才会扩展别名(因此它兼作语法检查器)。

bashMCE 相反,它还完全解析了别名。例如,如果您有:

$ alias ll='ls -l'; alias ls='ls --color'
$ ll

将扩展为:

$ ls --color -l

请注意,它还规范化了语法,例如:

$ for i (*) cmd $i; foo

将更改为:

$ for i in *
        do
                cmd $i
        done
        foo

答案2

如果将命令行填充到函数定义中,然后打印出该函数,则别名将被扩展。您还将获得标准化的空白。

% alias foo='bar -1'
% alias bar='qux -2'
% f () foo -3
% which f
f () {
        qux -2 -1 -3
}

要将所有这些放入交互式命令中,您可以制作一个 zle 小部件。您可以通过将其代码填充到函数的条目中来直接定义函数functions大批;当你回读时,你会得到标准化效果。

normalize-command-line () {
  functions[__normalize_command_line_tmp]=$BUFFER
  BUFFER=${${functions[__normalize_command_line_tmp]#$'\t'}//$'\n\t'/$'\n'}
  ((CURSOR == 0 || CURSOR = #BUFFER)
  unset 'functions[__normalize_command_line_tmp]'
}
zle -N normalize-command-line
bindkey … normalize-command-line

您会得到相同的归一化效果preexec。别名也会在函数自动加载时扩展(autoload -U通常用于避免别名扩展)。

_expand_alias如果光标下的单词是别名,则补全函数会展开该单词。它使用aliases大批。它不是递归的。您可以使用 实现更通用的别名扩展器aliases,但这有些困难,因为确定别名扩展的位置与 shell 语法密切相关。

答案3

如果您有许多嵌套的花哨别名,并且不确定 zsh 实际上对它们做了什么以及选项传递给命令的顺序,那么您始终可以使用-xoption 启动 zsh。这将在执行时打印命令和参数。

但请注意,此选项旨在用于调试目的,因此它在zsh -x调用后会打印很多无用的内容(基本上是 .zshrc 的每个函数/小部件/插件),并且在命令执行期间它也可能很冗长,尤其是如果你已经定义preexecprecmd挂钩。

我还应该提到,它打印仅有的最终执行的命令,以及单独的命令分别打印,因此之后

alias a='echo a'
alias b='echo b'
alias c='echo c'
alias d='echo d'
a && b || c; d

你会看见

+zsh:1> echo a
a
+zsh:1> echo b
b
+zsh:1> echo d
d

相关内容