【问题标题】:Bash (or other shell): wrap all commands with function/scriptBash(或其他 shell):用函数/脚本包装所有命令
【发布时间】:2013-12-11 16:50:32
【问题描述】:

编辑:这个问题最初是特定于 bash 的。我仍然希望有一个 bash 解决方案,但如果有一种在另一个 shell 中执行此操作的好方法,那么了解它也会很有用!

好的,问题的*描述。我希望能够在 bash 中添加一个钩子,这样,当用户输入时,例如$cat foo | sort -n | less,它会被拦截并翻译成wrapper 'cat foo | sort -n | less'。我已经看到了在每个命令之前和之后运行命令的方法(使用 DEBUG 陷阱或 PROMPT_COMMAND 或类似方法),但没有关于如何拦截每个命令并允许它由另一个进程处理。有没有办法做到这一点?

关于我为什么要这样做的解释,以防人们有其他解决方法的建议:

script 之类的工具可让您将您在终端中所做的一切记录到日志中(在某种程度上,就像 bash 历史记录一样)。但是,它们做得不是很好 - 脚本将输入和输出混合成一个大字符串,并与占据屏幕的 vi 等应用程序混淆,历史记录只为您提供输入的原始命令,而且它们都不起作用好吧,如果您同时将命令输入到多个终端中。我想做的是捕获更丰富的信息——例如,命令、执行时间、完成时间、退出状态、stdin 和 stdout 的前几行。我还希望将其发送到某个可以愉快地多路复用多个终端的监听守护进程。做到这一点的简单方法是将命令传递给另一个程序,该程序可以执行 shell 以将命令作为子进程处理,同时获取标准输入、标准输出、退出状态等的句柄。可以编写一个 shell 来执行此操作,但是你' d 失去了 bash 中已有的大部分功能,这很烦人。

这样做的动机来自于试图理解探索性数据分析,如事后程序。有了像这样更丰富的信息,就有可能生成关于所发生事件的体面报告,将一个命令的多次调用压缩到一个命令中,前几个给出非零退出,通过搜索文件的所有内容来询问文件来自哪里,等等等等。

【问题讨论】:

  • 如果不修改 bash 本身,这是不可能的。这在你的可能性范围内吗?即使那样,它也可能被证明是困难的。您的“命令”概念可能与任何内部 bash 结构都不对应。请参阅此答案中的奇怪示例:*.com/questions/20039771/…
  • 遗憾的是,修改 bash 并不是我真正想要考虑的选项!
  • 与其自己编写 shell 或修改 bash,不如对其他 shell 开放(我特别想到 zsh 和 fish)。
  • 这很好。我会向其他 shell 提出这个问题。
  • 这听起来类似于服务器处理请求的方式。例如,Apache 以不同程度的详细程度来实现它,并且在 Node、Ruby 和其他语言中有一堆模块。也许您可以对每个命令提出请求?工作量很大,它会增加您的互联网费用,但如果没有更好的方法......

标签: linux bash shell zsh fish


【解决方案1】:

运行这个 bash 脚本:

#!/bin/bash
while read -e line
do
    wrapper "$line"
done

在其最简单的形式中,wrapper 可以由 eval "$LINE" 组成。你提到想要有时间,所以也许有time eval "$line"。您想捕获退出状态,因此后面应该跟save=$? 行。而且,您想捕获标准输出的前几行,因此需要进行一些重定向。以此类推。

更多:Jo So 建议包含对多行 bash 命令的处理。以最简单的形式,如果 eval 返回“语法错误:文件意外结束”,那么您希望在继续之前提示输入另一行。更好的是,要检查正确的 bash 命令,请在执行 eval 之前运行 bash -n <<<"$line"。如果bash -n 报告行尾错误,则提示输入更多输入以添加到`$line'。以此类推。

【讨论】:

  • 这并不能真正解决问题,因为完整的命令通常不会占用一行
  • @JoSo 没那么难。
  • 这基本上是我在问题中提到的“实现自己的 shell”的简单版本,并且遇到了同样的问题:即,您无法访问各种 shell 生产力功能,例如历史,选项卡完成和反向搜索。
  • 要获得 readline 功能(制表符补全等),只需将 -e 选项添加到 read。 (Bash 擅长模仿 bash。)如果你找到了一种比我建议的更简单的方法来解决整个问题,那么当然可以使用它。
  • 建议:获取该文件,不要将其作为子shell运行;直接嵌入包装逻辑;使用eval "$line"
【解决方案2】:

我想到了 Binfmt_misc。 Linux 内核具有允许识别任意可执行文件格式并将其传递给用户应用程序的能力。

您可以使用此功能来注册您的包装器,但它应该处理所有可执行文件,而不是处理任意可执行文件。

【讨论】: