Bash 和 Zsh 是否有一种模式可以回显按下 Enter 时别名扩展的内容?

Bash 和 Zsh 是否有一种模式可以回显按下 Enter 时别名扩展的内容?

例如,如果我有一个

alias dbmigrate='rails db:migrate'

是否有一种模式或简单的方法可以在 Bash 和 Zsh 中进行配置,以便当我在 shell 中键入时:

$ dbmigrate  # press Enter

它会在运行之前回显别名扩展为什么?

答案1

巴什,有alias-expand-linehistory-and-alias-expand-linereadline 函数,但默认情况下它们不绑定到任何键。您可以自己绑定它们 - 例如Control-T

bind '"\C-T": history-and-alias-expand-line'

尝试绑定Enter自身会很混乱,因为并非任何时候您按下Enter都会执行命令(例如,当它是不完整的管道时,等等)。

还有一个DEBUG陷阱,但是确定该命令是否实际上是由用户输入的(例如,不是从PROMPT_COMMAND中的命令替换启动的PS1),以及它是否是别名扩展的,这将是很棘手的;但如果你同意打印任何执行前的命令:

trap 'echo "> $BASH_COMMAND"' DEBUG

bash$ pwd
> pwd

桀骜,您可以简单地定义一个preexec函数,如果与用户输入的命令不同,则打印扩展命令:

preexec(){ [ $1 != $2 ] && print -r "> $2" }

zsh$ j
> jobs

但请注意,如果强制扩展别名,某些别名+历史记录技巧将无法正常工作。例如,我c在 bash 中有一个别名来执行诸如 之类的计算c 3.17 * 4.2,而不必转义*,(等:

alias c='_c=$(fc -nl -0); bc -l <<<${_c#*c} #'

一旦 readline 展开它,历史记录中的当前行(由 返回的行fc -nl -0)将是扩大,不是原来的命令,一切都会崩溃。

答案2

别名只是简单的替换。如果您想做一些更奇特的事情,例如在运行命令之前打印一条消息,您需要更强大的东西:函数。如果您希望定义看起来像别名定义,则可以定义一个定义函数的函数。

function verbose_alias {
  local name=${1%%=*} expansion=${1#*=}
  eval "function $name {
    printf >&2 '%s is an alias for %s\\n' \"$name\" \"$expansion\";
    $expansion \"\$@\";
  }"
}
verbose_alias dbmigrate='rails db:migrate'

答案3

POSIX 要求set命令有这个选项

-x

   shell 应在扩展命令之后和执行命令之前向标准错误写入每个命令的跟踪。未指定是否跟踪关闭跟踪的命令。

https://pubs.opengroup.org/onlinepubs/009604499/utilities/set.html

因此您可以在任何兼容的 shell 上使用set -x或。set -o xtrace在 bash 中,您可以在手册页中看到这一点:

-x

   展开每个简单命令、for 命令、case 命令、select 命令或算术 for 命令后,显示 PS4 的展开值,后跟该命令及其展开参数或关联的单词列表。

xtrace

   与...一样-x

https://linux.die.net/man/1/bash

zsh 也有类似的选项set内置

XTRACE-x,克什-x:)

   执行命令时打印命令及其参数。

https://linux.die.net/man/1/zshoptions

您还可以-x在执行脚本或命令时指定选项

bash -x -c "echo This will be printed before running; ll"
bash -x script-to-be-debugged.sh
zsh -x -c "...; 3; md did-you-see-the-aliases"
zsh -x buggy-script.sh

请注意,它还扩展了每个提示之前和之后运行的命令,因此在许多情况下可能并不理想,例如当您git在 PS1 中使用变量时。在我干净的 Ubuntu VM 中,仅打印出正在运行的命令

也可以看看有什么set -x作用?

另一个选项是set -vorset -o verbose在打印之前不扩展变量

答案4

bash 默认情况下不提供这种帮助。

默认情况下可用的两个相关函数是:

  • shopt -s histverify

如果设置并且正在使用 readline,则历史替换的结果不会立即传递到 shell 解析器。相反,生成的行将加载到读取行编辑缓冲区中,从而允许进一步修改。

它解决了按下时的操作部分Enter,但仅在命令行上具有历史扩展。例如:

$ shopt -s histverify
$ echo "this is a test"
This is a test
$ echo !!
$ echo echo "this is a test"  <---- expanded by the simple use of enter!! 
  • 阅读线shell-expand-line

外壳扩展线 (MCe)

像 shell 一样展开该行。这将执行别名和历史扩展以及所有 shell 字扩展。有关历史扩展的描述,请参阅下面的历史扩展。

这正是您要求完成的,但使其发挥作用的关键是Ctrl- Alt-e

shell-expand-line抱歉,我不知道与 Enter 和executes 一起使用的解决方案。

相关内容