Bash sh-c不合理性与以编程方式确定和运行Linux内置命令

Bash sh-c不合理性与以编程方式确定和运行Linux内置命令,bash,shell,command-line-interface,Bash,Shell,Command Line Interface,我需要从程序中确定Linux命令是否为内置命令。我还需要偶尔运行这个内置命令。我将以alias为例,它也适用于其他内置软件 我发现一个恰当的答案是: sh -c 'type alias' 这将返回“alias是一个shell内置”,这正是我所需要的。但是…我还需要运行它。我所做的任何尝试都无法做到这一点。所有这些都会在终端窗口中以编程方式失败: sh-c“别名”没有任何输出 sh-c“命令别名”没有任何输出 sh-c“内置别名”sh:1:未找到内置名 sh-c“类型内置”内置:未找到 sh-c

我需要从程序中确定Linux命令是否为内置命令。我还需要偶尔运行这个内置命令。我将以alias为例,它也适用于其他内置软件

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

sh -c 'type alias'
这将返回“alias是一个shell内置”,这正是我所需要的。但是…我还需要运行它。我所做的任何尝试都无法做到这一点。所有这些都会在终端窗口中以编程方式失败:

sh-c“别名”没有任何输出 sh-c“命令别名”没有任何输出 sh-c“内置别名”sh:1:未找到内置名 sh-c“类型内置”内置:未找到 sh-c“type command”命令是一个shell内置命令 sh-c“type”类型是一个shell内置类型 几乎不用说,所有这些命令(例如,没有sh-c)在终端上都可以正常工作。这让我对sh-c命令看似不合理的本质感到困惑

我的问题是:所有Linux版本都是这样吗?我是否缺少开关或设置?那么,我如何从一个程序中执行一个内置项,以便恢复其输出呢

我正在研究Kubuntu 14.04,在Trisquel中也是如此;此问题发生在konsole和xterm以及编程调用中

感谢您的评论和回答,非常感谢

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

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

例如,这在基于文件的命令rsync等方面非常有效,我在输入和输出文本方面没有问题。我甚至可以简单地将一个进程的输出传递到另一个进程的输入,从而复制管道。但是

…内置的就不是这样了。这让我开始研究别名等等

我希望我的程序也包括内置的,但第一个问题是,当它被添加时,如何判断它是否是内置的是,内置的列表是有限的,但后来它可以扩展,我希望我的程序能够处理这种可能性。因此,我研究并发现了sh-c“类型cmd”

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

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

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

我现在确实理解了subshell的概念,这也解释了为什么我没有得到任何东西,因为我怀疑它与输出有关

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

那么,有没有办法将子shell的输出返回到我启动的流程?请记住,我是通过我创建的一个程序来编程的,但这个问题也反映在终端上,同样的事情也会发生

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

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

简单地通过我创建的进程运行命令会导致一个异常,因为进程对shell一无所知,所以只运行文件,没有找到内置的,所以失败,这就是为什么sh-c或类似的东西是我唯一的选择

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


最后一个观察:为什么sh-c的“类型别名”可以工作?如果sh-c“command alias”的原因是因为它是子外壳的,所以没有返回任何输出,那么为什么类型版本可以工作?类型是特殊的?这就是我看到的不合理之处。

当您使用bash-c或sh-c运行某个命令时,一个新的shell被分叉。相反,当您使用source somefile或。somefile一些文件,当前shell进程正在读取它,同样

任何内置命令(如alias、cd或ulimit)都只会影响当前的shell进程。因此,如果您使用sh-c运行它,则只会影响运行它的新shell,而不会影响在终端中运行的父shell

这里没有非理性。顺便说一句,您可以尝试bash-c'echo$$与echo$$,因为$$给出了当前shell的pid

我建议读一读


还要注意,system和popen都隐式地使用/bin/sh-c,并且期望使用与POSIX兼容的shell,它与/bin/bash-c不同。阅读并注意到,并非每个shell都是特定的,也不是启动交互式shell。

当您使用bash-c或sh-c运行某个命令时,会生成一个新的shell。相反,当您使用source somefile或。somefile一些文件,当前shell进程正在读取它,同样

任何内置命令(如alias、cd或ulimit)都只会影响当前的shell进程。因此,如果您使用sh-c运行它,则只会影响运行它的新shell,而不会影响在终端中运行的父shell

这里没有非理性。顺便说一句,您可以尝试bash-c'echo$$与echo$$,因为$$给出了当前shell的pid

我建议读一读

还要注意,system和popen都隐式地使用/bin/sh-c,并且期望使用与POSIX兼容的shell,它与/bin/bash-c不同。请阅读并注意,并非每个shell都是特定的,也不是启动交互式shell。

好的内置程序由当前shell直接执行,因此命名为。。。。因此,如果您希望允许cd或alias等命令,或者希望允许用户更改环境变量,则必须在自己的shell中明确地为此编写代码

唯一好的新功能是,一些内置代码只集成到shell中,以加快直接执行的处理速度,而无需派生新的进程,但也可以作为实际命令存在。尝试在路径中找到它们以确保。

好的内置代码由当前shell直接执行,因此命名为。。。。因此,如果您希望允许cd或alias等命令,或者希望允许用户更改环境变量,则必须在自己的shell中明确地为此编写代码


唯一好的新功能是,一些内置代码只集成到shell中,以加快直接执行的处理速度,而无需派生新的进程,但也可以作为实际命令存在。尝试在路径中找到它们,以确保一致性。

您在错误的地方寻找一致性,因为您缺少这些命令中某些命令正在执行的关键方面。在不同的上下文中运行相同的命令可能会产生不同的结果。例如,如果在没有参数的情况下运行ls或pwd,则结果取决于当前目录

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

命令alias打印出在当前shell中定义的别名列表。别名是外壳内部状态的一部分。如果您运行一个新的shell实例,它将在没有定义别名的情况下启动,因此alias将打印一个空列表。通常,在运行交互式shell时,别名是启动文件定义的别名,例如~/.bashrc,这就是alias列出的别名。但是,如果在命令行上运行alias或unalias,则可以更改该shell实例的别名,而这不会影响其他shell尝试一下,以确保了解发生了什么。 由于alias是内置的,因此命令alias执行与alias相同的操作。 内置别名与bash中的别名执行相同的操作。内置命令是bash内置命令。其他外壳中不存在内置元素;在Ubuntu上,/bin/sh不是bash,而是dash,一个更小、更快、兼容POSIX但缺少bash更高级功能的shell。这也解释了内置类型。bash-c“type builtin”将报告builtin是一个内置的。 type command和type type报告command和type是内置的,因为它们在sh中是内置的。 不能从程序中执行内置代码:内置代码是特定shell的命令。您可以执行一个支持该内置代码的shell,并告诉它执行该内置代码,但当然,该内置代码是在该shell的上下文中执行的

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

“CLI帮助程序GUI”已存在:它被调用
终端仿真器。听起来您想制作一些更受约束的GUI,它只能执行某些特定的命令。在这种情况下,我认为公开别名等特性是没有意义的。这里您并没有提供一个shell接口,而是提供了一个运行程序的接口。你不是在连接外壳,而是在替换它。因此,不要考虑shell命令,要考虑运行程序。没有名为alias的程序。

您在错误的地方寻找一致性,因为您缺少某些命令所执行的关键方面。在不同的上下文中运行相同的命令可能会产生不同的结果。例如,如果在没有参数的情况下运行ls或pwd,则结果取决于当前目录

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

命令alias打印出在当前shell中定义的别名列表。别名是外壳内部状态的一部分。如果您运行一个新的shell实例,它将在没有定义别名的情况下启动,因此alias将打印一个空列表。通常,在运行交互式shell时,别名是启动文件定义的别名,例如~/.bashrc,这就是alias列出的别名。但是,如果在命令行上运行alias或unalias,则可以更改该shell实例的别名,而这不会影响其他shell尝试一下,以确保了解发生了什么。 由于alias是内置的,因此命令alias执行与alias相同的操作。 内置别名与bash中的别名执行相同的操作。内置命令是bash内置命令。其他外壳中不存在内置元素;在Ubuntu上,/bin/sh不是bash,而是dash,一个更小、更快、兼容POSIX但缺少bash更高级功能的shell。这也解释了内置类型。bash-c“type builtin”将报告builtin是一个内置的。 type command和type type报告command和type是内置的,因为它们在sh中是内置的。 不能从程序中执行内置代码:内置代码是特定shell的命令。您可以执行一个支持该内置代码的shell,并告诉它执行该内置代码,但当然,该内置代码是在该shell的上下文中执行的

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


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

sh-c打开一个未定义别名的子shell。这就是为什么它一无所获。试试bash-c'别名a=blah;alias'您可以在bash脚本中使用type命令,然后根据返回字符串以编程方式决定要执行的操作。内置程序的列表变化不大。你为什么认为你需要做实验?为什么它们是内置的与否很重要?只需运行这些命令-它们应该可以工作。为什么需要运行alias?任何人都不应该使用别名。CLI helper GUI不应该使用shell—不应该使用sh-c或bash-c或其他任何东西—除非您真的知道自己在做什么。Shell注入攻击和SQL注入攻击一样都是一个问题。如果您的用户在其配置中指定了一个文本argv数组,那么他们可以指定一个shell,如果并且仅当他们确实需要并且有理由这样做。sh-c打开一个没有定义别名的子shell。这就是为什么它一无所获。试试bash-c'别名a=blah;alias'您可以在bash脚本中使用type命令,然后根据返回字符串以编程方式决定要执行的操作。内置程序的列表变化不大。你为什么认为你需要做实验?为什么它们是内置的与否很重要?只需运行这些命令-它们应该可以工作。为什么需要运行alias?任何人都不应该使用别名。CLI helper GUI不应该使用shell—不应该使用sh-c或bash-c或其他任何东西—除非您真的知道自己在做什么。Shell注入攻击和SQL注入攻击一样都是一个问题
ks。如果您的用户在其配置中指定了文字argv数组,那么他们可以指定一个shell,前提是他们确实需要并且有理由这样做。是的,我已经看到了…例如pwd。是的,我已经看到了…例如pwd。感谢您提供的见解,他们很有帮助。我不知道你是否看到了我更新的问题,不知道你是否对此有任何见解:>为什么有效?如果sh-c“command alias”的原因是因为它是子外壳的,所以没有返回任何输出,那么为什么类型版本可以工作?类型是特殊的?这就是我看到非理性的地方,嗯?sh-c“command alias”不返回任何输出,因为shell中没有别名,而不是subshell,这是另一个事物的特定术语。它不会因为成功运行时的输出列表为空而停止作为有效命令。这是一个完全有效的命令,空列表是完全有效的成功输出。如果它没有成功运行,您将在stderr中打印一个错误。请考虑您是否正在运行grep foo/dev/null。输出为空并不意味着grep没有运行。类似地,您的代码在一个非交互shell中成功运行了alias命令,因此,该shell没有源代码~/.bashrc[您不应该期望一个以sh-c而不是bash-c启动的shell是bash]并且没有定义别名。好的。你们真是太棒了。现在一切都清楚了。我找到了答案,它工作得很好:bash-I-c“command alias”返回输出,yesss。太好了,非常感谢大家。哦,请原谅我可能会混淆术语,我仍然处于lunux学习模式。我还想感谢高级linux编程的链接,内容非常丰富,我推荐给其他在linux学习模式下阅读本文的人。感谢您的见解,他们很有帮助。我不知道你是否看到了我更新的问题,不知道你是否对此有任何见解:>为什么有效?如果sh-c“command alias”的原因是因为它是子外壳的,所以没有返回任何输出,那么为什么类型版本可以工作?类型是特殊的?这就是我看到非理性的地方,嗯?sh-c“command alias”不返回任何输出,因为shell中没有别名,而不是subshell,这是另一个事物的特定术语。它不会因为成功运行时的输出列表为空而停止作为有效命令。这是一个完全有效的命令,空列表是完全有效的成功输出。如果它没有成功运行,您将在stderr中打印一个错误。请考虑您是否正在运行grep foo/dev/null。输出为空并不意味着grep没有运行。类似地,您的代码在一个非交互shell中成功运行了alias命令,因此,该shell没有源代码~/.bashrc[您不应该期望一个以sh-c而不是bash-c启动的shell是bash]并且没有定义别名。好的。你们真是太棒了。现在一切都清楚了。我找到了答案,它工作得很好:bash-I-c“command alias”返回输出,yesss。太好了,非常感谢大家。哦,请原谅我可能会混淆术语,我仍然处于lunux学习模式。我还想感谢您提供了指向高级linux编程的链接,内容非常丰富,我推荐给其他在linux学习模式下阅读本文的人。是的!谢谢,我现在已经清楚了概念。在理解了你精彩的解释之后,我找到了答案!我会把它贴在下面。是的!谢谢,我现在已经清楚了概念。在理解了你精彩的解释之后,我找到了答案!我会把它贴在下面。