【问题标题】:Can I react on entered command in bash?我可以对 bash 中输入的命令做出反应吗?
【发布时间】:2017-04-05 10:18:58
【问题描述】:

我想以某种方式配置我的 bash,以便我对用户输入命令的事件做出反应。他们按下 Enter 的那一刻,我希望我的 bash 运行我首先安装的脚本(类似于任何PROMPT_COMMAND,每次发出提示时都会运行)。这个脚本应该可以

  • 查看输入的内容,
  • 也许可以改变它,
  • 甚至可以让 shell 忽略它(即让它不执行该行),
  • 决定是否将文本插入历史记录,
  • 也许还有类似的东西。

我还没有找到合适的方法来做到这一点。我当前的实现都是有缺陷的,并且在执行命令之前使用调试陷阱进行干预,或者在执行命令之前使用(HISTTIMEFORMAT='%s '; history 1) 来询问历史命令执行完成后关于命令启动时的事情等(但是只是事后诸葛亮,这并不是我真正想要的)。

我希望有类似 COMMAND_INTERCEPTION 的变量,它的工作方式类似于 PROMPT_COMMAND,但我找不到类似的东西。

我也考虑过使用命令行完成来实现我的目标,但无法找到任何关于在此发送完成的命令时做出反应的信息,但也许我只是没有找到它。

任何帮助表示赞赏:)

【问题讨论】:

  • 几天前我发了一个关于measuring time of commands in bash using PS0 and PS1的问题的答案。我相信您可以在PS0 中“嵌入”您的操作。因此,该链接可能会为您提供必要的灵感(尽管我真的不确定“干预”、“交换输入命令”等,即如何使其工作。)
  • PS0, nice :) 不幸的是,我的 Ubuntu 16.04(最新的 LTS 版本)仍然包含一个没有那个补丁的 bash,所以它对 PS0 一无所知.此外,从我读到的内容来看,这个 PS0 无法访问给定的命令,无法读取或更改它。但无论如何感谢PS0 的提示!至少对于未来的设置,我可能会使用这个。
  • 所以,我猜你的解决方案有点像DEBUG trap and PROMPT_COMMAND in Bash(但可能更复杂)。顺便提一句。我什至没有注意到PS0 是一个如此新的 bash 功能。谢谢,我又学到了一些新东西......
  • PS0 是 bash-4.4 中新增的。

标签: linux bash shell interceptor prompt


【解决方案1】:

您可以使用DEBUG 陷阱和extdebug feature,并从陷阱处理程序中窥视BASH_COMMAND 以查看正在运行的命令。 (尽管如 cmets 中所述,调试陷阱出现在每个简单命令上,而不是每个命令行上。子shell也会避开它。)

调试处理程序可以阻止命令运行,但不能直接更改它。当然,您可以在调试器中运行任何命令,可能使用 BASH_COMMANDeval 构建它,然后告诉 shell 忽略原始命令。

这将阻止运行以ls 开头的任何内容:

$ preventls() { case "$BASH_COMMAND" in ls*) echo "no!"; return 1 ;; esac; }
$ shopt -s extdebug
$ trap preventls DEBUG
$ ls -l
no!

使用trap - DEBUG 移除陷阱。在 Bash 4.3.30 上测试。

【讨论】:

  • \ls or 'ls' or a= ls etc.
  • @gniourf_gniourf,还是/bin/ls?我没有说它不能解决。鉴于它是用于调试而不是安全性,我也没有真正看到那里有问题。
  • 没错,我对安全问题或沙盒化不感兴趣。我喜欢安慰我的工作。但是另一个问题更让我困扰:如果我输入像true | true | false | false 这样的管道,则该调试脚本会为管道的每个部分单独调用(每个true 一次,每个false 一次),甚至一次我的PROMPT_COMMAND。这有点问题,因为我无法通过自己执行某些操作来更改管道上下文中的命令。
  • @Alfe,嗯,是的,文档说它会为每个 简单命令 设置陷阱,因此管道的每个部分都是独立的。如果您主要关心交互式输入的命令,最好查看 readline 和命令行编辑功能。但我不确定可以用它们做什么,抱歉。
  • :) 无论如何感谢extdebug 及其功能的提示。它有更多方面有时可能会派上用场,另一方面可能是个问题,因为我真的不希望它们一直处于活动状态:-}
最近更新 更多