sh -c 非理性并以编程方式确定和运行 Linux 内置命令

juu*_*uus 1 bash shell command-line-interface

我需要从程序中确定 Linux 命令是否是内置命令。我还需要偶尔运行该内置命令。我将使用别名作为示例,它也适用于其他内置函数。

我发现的一个恰当的答案是使用:

sh -c 'type alias'
Run Code Online (Sandbox Code Playgroud)

这将返回 'alias is a shell builtin',正是我所需要的。但是...我也需要运行它。我尝试过的任何事情都不会这样做。所有这些都在终端窗口中失败(并以编程方式):

  • sh -c 'alias' (没有任何输出)
  • sh -c 'command alias' (没有任何输出)
  • sh -c 'builtin alias' (sh:1:内置:未找到)
  • sh -c 'type builtin' (内置:未找到)
  • sh -c 'type command' (命令是内置的shell)
  • sh -c 'type type' (类型是内置的外壳)

(几乎)不用说,所有这些命令(即没有sh -c)在终端上都可以正常工作。这让我对sh -c命令看似不合理的性质感到困惑。

我的问题是:所有 Linux 版本都是这样吗?我是否缺少开关或设置?那么,我如何从程序中执行内置函数以取回其输出?

我正在开发 Kubuntu 14.04(在 Trisquel 中也是如此);此问题发生在konsolexterm和程序化调用中。


感谢您的评论和回答,不胜感激。

我确实需要澄清我在做什么:我正在编写一个 CLI 助手 GUI,一个存储最喜欢的 linux 命令并执行它们的程序。

我使用 freepascal/Lazarus,它有一个 TProcess 类,可以启动一个进程并提供对 stdin、stdout 和 stderror 的访问权限。

这对于基于文件的命令(例如 rsync 等)非常有效,并且我输入和输出文本没有问题。我什至可以复制管道,只需将输出从一个进程传递到另一个进程的输入。但...

...不是这样的内置。这让我开始了研究别名等的道路。

我希望我的程序也包含内置程序,但第一个问题是如何在添加时判断它是否是内置程序(是的,内置程序列表是有限的,但稍后可以扩展,我希望我的程序能够处理那种可能性)。因此我研究并发现了 sh -c 'type cmd'。

现在我可以确定命令是基于文件的(使用 which)还是内置的(使用上面的表达式)。

虽然通过我的程序运行内置函数不会有很大的调用,但偶尔从一个程序中获取输出是有用的。例如别名。alias 在没有参数的情况下运行时等效于 alias -p ,它只是输出系统中注册的当前别名。

但问题就在这里。正如我上面所示,我似乎无法获得输出。

我现在明白了 subshel​​l 的概念,这就解释了为什么我什么也没有得到回报(我怀疑它以某种方式与输出相关)。

不幸的是,到目前为止所有的建议都不起作用。例如, eval 命令(谢谢你,我不知道那个)。它是一个内置的。因此,我知道(尝试)获取输出的唯一方法是使用 sh -c 'eval alias',它不返回任何内容,因为它是子壳。

那么有没有办法让子shell的输出回到我开始的过程?请记住,我是通过我创建的进程以编程方式执行此操作的(但此问题也反映在终端中,同样的事情也会发生)。

我还想评论其他一些评论:

是的,我一直在考虑写出一个 bash sh 文件并运行它,但我不会遇到同样的问题吗?

简单地运行命令(通过我创建的进程)会导致异常,因为该进程对 shell 一无所知,因此只运行文件,找不到内置文件,因此失败,这就是 sh -c 或类似内容的原因,是我唯一的选择。

为什么我需要运行别名?嗯,这只是一个例子,就像我说这是一个内置问题,我使用别名作为例子。但是,就我个人而言,我喜欢别名,也许我的一些用户也喜欢。

最后一个观察:为什么sh -c 'type alias'有效?如果原因不sh -c 'command alias'返回任何输出,因为它是 sub-shelled 那么为什么type版本有效?类型是特殊的?这就是我看到的非理性之处。

Gil*_*il' 5

您在错误的地方寻找一致性,因为您错过了其中一些命令正在执行的操作的关键方面。在不同的上下文中运行相同的命令可能会产生不同的结果。例如,如果您运行lsor pwd(不带参数),结果取决于当前目录。

二分法不是在内置命令和非内置命令之间,而是在行为受运行它们的 shell 影响的命令和不受其影响的命令之间。存在相关性:大多数受运行它们的 shell 影响的命令都是内置的,因为外部命令将无法访问运行它们的 shell 的状态。

  • 该命令alias打印出当前 shell 中定义的别名列表。别名是外壳内部状态的一部分。如果你运行一个新的 shell 实例,它开始时没有定义别名,所以alias打印一个空列表。通常,当您运行交互式 shell 时,您的别名是由您的启动文件(例如~/.bashrc)定义的别名,这就是alias列表。但是,如果您在命令行上运行aliasunalias,您可以更改该 shell 实例的别名,而这不会影响其他 shell(尝试一下以确保您了解发生了什么)。
  • command alias做同样的事情,alias因为alias是内置的。
  • builtin aliasaliasbash做同样的事情。该builtin命令是内置的 bash。builtin不存在于其他壳中;在 Ubuntu 上,/bin/sh不是 bash 而是 dash,一个更小、更快且符合 POSIX 标准的 shell,但缺少 bash 的一些更高级的功能。这也说明了type builtinbash -c 'type builtin'会报告这builtin是一个内置的。
  • type commandtype type报告commandtype是内置的,因为它们是内置的sh.

您不能从程序中执行内置命令:内置命令是特定 shell 的命令。您可以执行支持此内置命令的 shell 并告诉它执行该内置命令,但当然内置命令是在该 shell 的上下文中执行的。

你不能alias从 Pascal 程序中执行命令,就像你不能调用 Pascalwrite从 shell 程序函数一样。shell 内置函数是 shell 的库函数。Shell 模糊了它们自己的函数和外部程序之间的区别,因为您可以使用相同的语法调用外部程序,而不是通过类之TProcess类的东西,但归根结底,概念是相同的。

“CLI helper GUI”已经存在:它被称为终端模拟器。听起来您想要制作一些只能执行某些特定命令的更受限制的 GUI。在这种情况下,我认为公开别名等功能没有意义。您在这里没有提供 shell 的接口,而是提供了一个运行程序的接口。您不是在与外壳接口,而是在替换它。所以不要想shell命令,想运行程序。没有名为 的程序alias