识别所键入命令的别名

识别所键入命令的别名

是否有任何 shell/shellscript 可以识别我在命令行中键入的命令已经有一个别名。

例如

在外壳上我输入

git checkout master

贝壳印花"You can use alias you have for that : gcm"

然后 Shell 像平常一样继续检查 master。

我知道该alias命令列出了所有可用的别名。我希望 shell 在我不使用别名并键入完整命令时提醒我使用别名。

答案1

这是一种概念方法可能工作。

alias命令生成所有别名的列表,每个别名后跟一个=和它的定义。可以通过从第一个空格和第一个 之间提取别名名称来解析此输出=。第一个之后的所有内容=都是要匹配的定义。这听起来像是使用 awk 中的关联数组轻松处理的事情。

(我看到)这有两个复杂之处:

1)由于定义可以由多个单词组成,因此您必须执行一些操作,例如测量定义的长度减去任何封闭的引号,并将与输入的命令的比较限制为该长度。

2)别名可以包含一些奇怪的东西。这是我最奇怪的一个(我相信他们会变得更奇怪):

alias pqp='cd ~/pq;[ -n "$(ls)" ] && mprb * || echo "Print Queue Empty"'

这里的要点是,别名可以包含(几乎?) shell 想要解释和扩展的所有特殊字符,因此最好使用 awk 或 Python 等其他语言进行编码,其中将处理您需要比较的两个字符串作为简单的字符串。

下一个问题是您希望在完成匹配和发出任何消息后实际运行该命令。

这里需要担心的是,您在程序中运行的任何内容,即使它只是另一个脚本,也将(通常)在子进程中执行。这意味着当命令终止并且子 shell 关闭时,该命令的任何(shell 级)副作用都将丢失。最明显的是返回代码 ,$?您必须捕获它并重新发出它作为实用程序的返回代码。

如果别名包含使用source,.命令的调用,那么您将非常不走运,因为在子 shell 中运行该命令将完全取消预期的副作用。

Shell 包含许多内置命令,例如cd.其中一些具有与[和相同的程序/usr/bin/test,但有些则cd没有,甚至对于那些具有相同功能的程序,内置版本并不总是具有与外部版本相同的行为和选项。

之所以存在上述问题,是因为最终命令来自当前 shell 级别的标准输入之外的其他位置,因此处理方式有所不同。这就是类似的地方自动键或许能帮上忙。

AutoKey 是一个宏处理器,可用于在 X (gui) 环境中自动执行各种操作。在这种情况下,当您按下用户定义的热键时,它可用于调用宏。该宏可以读取并分析您要输入的命令行,发出任何消息(有关别名等),然后重新输入该命令,就像在键盘上输入一样。

这里的优点是 Linux(实际上是您的桌面环境/终端仿真器)无法辨别是否是您键入的命令,并且一切都在您原始的本机环境中进行,就好像 AutoKey 根本不存在一样。

这种方法的第二个优点是,如果您只是输入命令而不先按热键,那么一切照常进行,没有任何开销等。

这让我想到了最后一点,这一点已经在 stackexchange 和其他地方的各个地方进行了详细讨论。

在用户(在本例中为您)完全可见的情况下,采用任何系统的正常部分并在幕后更改其默认工作方式几乎总是一个坏主意。

简而言之,如果您自定义系统以非标准方式运行,则会产生两个主要后果。

1) 如果其他人使用该系统(例如帮助您调试问题),他们将遇到意想不到的结果,这可能会产生许多不愉快的后果。

2)您习惯了修改后的行为,然后(无意识地)期望它在您使用未以相同方式定制的另一个系统时起作用。

典型的例子是定义一个别名,例如

alias rm='rm -i'

这听起来像是一个好主意,直​​到您在另一个系统上键入rm并且当您期望首先得到提示时文件会立即被删除。

解决这个问题的方法是这样的:

alias rmi='rm -i'

如果您键入它,它会起作用,但如果您在另一个系统上键入它,它可能除了发出命令未找到错误之外不会执行任何操作。

这在半夜尤其重要,因为当重要的东西坏了时,你没有像你希望的那样警觉,并且你面临着修复它的压力现在。当你真的不想要任何意想不到的行为或事情时,你必须浪费时间向人们解释。

它的工作方式与使用热键激活的 AutoKey 宏进行别名检查相同。如果您不特意通过按热键来激活宏,那么一切都会按照任何人的预期进行。正确选择的热键可能不会被意外按下,并且如果习惯性地在另一个系统上按下,也可能不会造成任何有害影响。

答案2

我有一个解决方案bash。您需要一个在每个命令之前执行的函数。由于bash本身不支持这一点,因此您必须使用DEBUG陷阱来解决该问题。

请参阅 bash 手册页的陷阱部分DEBUG

如果 sigspec 为 DEBUG,则命令 arg 在每个简单命令、for 命令、case 命令、select 命令、每个算术 for 命令之前以及在 shell 函数中执行第一个命令之前执行

所以该函数可能看起来像这样(第一部分是从该函数复制的超级用户回答):

preexec () {
  [ -n "$COMP_LINE" ] && return  # do nothing if completing
  [ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return # don't cause a preexec for $PROMPT_COMMAND
  local this_command=$(HISTTIMEFORMAT= history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//")
  # check if the command occures as an alias
  a=$(alias | grep -F "='""$this_command""'" | grep -oP '(?<=alias\ )[^=]+')
  # if yes, print a notice
  [ -n "$a" ] && echo -e "You can use an alias you have for that: \033[01;32m$a\033[00m"
}
trap 'preexec' DEBUG

输入时:

$ git checkout master

它打印:

You can use an alias you have for that: gcm

然后继续执行命令。

答案3

在更多地研究我想要的东西时发现了这个。

对于 zsh 有一个插件别名提示它已经做到了这一点。

相关内容