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


12

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

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


2
C-x a在光标下扩展别名(假设您正在使用完成系统)。
斯特凡Chazelas

是的_expand_alias (^Xa): expands the word the cursor is on if it is an alias。这很有帮助,但是遗憾的是,在bash中可以扩展整行,而在zsh中则不能。
WeSenseASoulInSearchOfAnswers 2014年

我想可以编写一个可绑定的命令,_expand_alias直到编辑缓冲区不再更改时才调用它。
vinc17

Answers:


10

请注意,Ctrl-Alt-E输入bash不仅会扩展别名。它还扩展变量,命令替换(!),进程替换(!),算术扩展并删除引号(它不执行文件名生成(globbing)或波浪号扩展)。

它并不总是设法扩展别名。因此,尽管有其用途,但重要的是要认识到其结果可能会更改命令行的含义,产生副作用并具有潜在危险。

例如在:

$ 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

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

bash的MCE 相反,它也可以完全解析别名。例如,如果您有:

$ 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

这是越野车。如果我alias ls='ls --color'输入C-x a了over ls,则得到:(\ls --color这样ls就不会将新名称误解为别名)。但是有了您expand-aliases,我得到了:ls --color,结果变得模棱两可。
vinc17 2014年

@ vinc17,它可以完全解析别名(在此方面,它比bash等效名称的错误更少)不是模棱两可的。但是,如果在此之后运行命令,则确实如此,您将获得另一轮别名扩展(如中的bash),因此理想情况下,您希望暂时禁用别名扩展,例如将其包装在中(){ setopt localoptions noexpandalias; ...; }。请注意,您可以说_expand_alias在运行时会出现问题,并且会扩展别名\ls
斯特凡Chazelas

@ vinc17,反斜杠转义_expand_alias也很容易被欺骗,就像alias 'foo=repeat 3 foo'alias ls='ls --color'; alias '\ls=echo fooled'。这里没有完美的解决方案。
斯特凡Chazelas

关于_expand_aliasalias 'foo=repeat 3 foo',我会认为丢失的反斜杠的错误。并且alias '\ls=echo fooled'不应该被允许;在这里,我更喜欢bash,它表示:bash: alias: '\ls': invalid alias name
vinc17 2014年

@ vinc17,除了中的限制外,我看不到该怎么看bash。如果您不喜欢带有反斜杠的别名,请不要使用它们,但是为什么要外壳程序拒绝它们呢?虽然别名是csh(它们来自何处)中的穷人功能替代品,但在类似于Bourne的shell中,它们是骇人的工具,可以做一些函数无法完成的技巧,某种形式的宏扩展会在shell解析器的早期挂勾,我看不出限制它可以做什么的意义。
斯特凡Chazelas

6

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

% 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

preexechook中,您可以获得相同的归一化效果。自动加载功能时,别名也会被扩展(autoload -U通常用于避免别名扩展)。

_expand_alias完成功能扩展光标下的单词,如果它是一个别名。它使用aliases数组。它不是递归的。您可以使用来实现更通用的别名扩展器aliases,但这有点困难,因为找出别名扩展的位置与shell语法紧密相关。


2
autoload -U之所以总是使用zsh文档,是因为它推荐这样做,但是-U直到我读到:)为止,我才真正理解了它的实际作用。同样,对于感兴趣的任何人,都可以通过在命令行中输入别名,点击,启动迷你缓冲区,然后键入<Esc>x_expand_alias<Enter>
–the_velour_fog

2

如果您有许多嵌套的花式别名,并且不确定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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.