为什么我的程序“ set”没有执行?


10

我创建了一个简单的C程序,如下所示:

int main(int argc, char *argv[]) {

    if (argc != 5) {
       fputs("Not enough arguments!\n", stderr);
       exit(EXIT_FAILURE);
    }

我在etc / bash.bashrc中修改了我的PATH,如下所示:

PATH=.:$PATH

我已经将该程序保存为set.c,并使用

gcc -o set set.c

在文件夹中

~/Programming/so

但是,当我打电话

set 2 3

什么都没发生。没有文字出现。

呼唤

./set 2 3

给出预期的结果

我以前从未遇到过PATH问题

which set

返回./set。因此,似乎PATH是正确的路径。发生什么事了?


10
添加“。”相对危险。到您的路径。最好是在本地目录中执行某些操作时使用./,或将可执行文件移至一个知名目录,例如〜/ bin /
TREE

7
test出于相同的原因调用测试程序也是一个坏主意。test也是内置的shell。
乔纳森·莱夫勒

@JonathanLeffler然而,对于快速测试而言,调用程序test似乎很有意义。当然,当您将其放入自己的笔记本电脑时,您PATH确实应该想出一个不同的名称。并且在将程序放入您的程序之前PATH./test无论如何都必须调用它。因此,可以使用test程序的名称,只要这是您打算在一天结束前删除的快速测试即可。
kasperd 2015年

1
@kasperd:据我所知,快速测试程序的常规名称是foo
hmakholm在

如果您命名它,ls那么只要您去查看它是否存在,它就会运行(但前提是您必须像在问题中一样修改路径)。
ctrl-alt-delor

Answers:


24

可以使用确定要在键入命令时运行的内容which,而不是使用,它在最需要时不起作用。type

$ which set
./set
$ type set
set is a shell builtin

Shell总是在搜索之前寻找内建函数$PATH,因此$PATH此处的设置无济于事。

最好将可执行文件重命名为其他名称,但是如果您的分配要求将程序命名为set,则可以使用shell函数:

$ function set { ./set; }
$ type set
set is a function
set ()
{
    ./set
}

(该方法在中有效bash,但其他shell ksh可能不允许使用。请参见mikeserv的答案以获取更便携的解决方案。)

现在键入set将运行名为“ set”的函数,该函数将执行./set。GNU bash在寻找内建函数之前先寻找函数,然后在搜索之前寻找内建函数$PATH。bash手册页中名为“ COMMAND EXECUTION”的部分提供了有关此内容的更多信息。

另请参阅builtin和上的文档commandhelp builtinhelp command


3
你建议typewhich,但不给任何理由。(我知道为什么,但是不需要推荐的人。)
cjm

1
@cjm这里有一个整体的论文,为什么不其中unix.stackexchange.com/questions/85249/...
安东尼纪勤

非常丰富。您永远都不会想到,执行如此简单任务的看似简单的命令会引起如此多的争议
Ganea Dan Andrei 2015年

4
@GaneaDanAndrei主要使用type而不是which,不要将您的程序命名为“ set”,而应意识到这function set { ./set; }是一个丑陋的骇客,您应该避免。
yellowantphil,2015年

11

set是bash内置的(可能还有其他大多数shell)。这意味着在寻找函数时,bash甚至不会搜索路径。

附带一提,.出于安全原因,我强烈建议您不要添加该路径。想象一下cd/tmp在其他任何用户添加了可执行文件之后,就会跳出来/tmp/cd


2
是的,这是一个愚蠢的主意,我的老师强迫我们以便在演示程序时不要显得不专业。“如果没有完成
会把您打分。– Ganea Dan Andrei 2015年

1
布朗尼给优秀老师的要点:(
klimpergeist

4
cd是内置的Shell,因此该示例由于与相同的原因而无法工作set
EmilJeřábek2015年

15
使用./foo调用程序专业的;它表明您了解为什么.不应该在$ PATH中。您的老师错了,您可能会告诉他我是这样说的。
zwol

10

set只是内置的,它是POSIX特殊的内置的。有哪些是标准的规定在其他任何命令之前搜索中发现了几个内置命令- $PATH不搜索,功能名称不搜索,等其最建宏不是 特别实际需要 POSIX标准是在您的shell中找到$PATH 之前,shell将运行其自己的任何内置程序。这是真实的echo,其余的大多数(但是否在这方面很荣幸的标准在过去在开放群组邮件列表一直是争论的问题),但不是settrapbreakreturncontinue.:timesevalexitexportreadonlyunset,或exec

所有这些都是外壳程序的保留名称,除了具有命令搜索的优先顺序之外,它们还具有特殊的属性。例如,您不能在符合标准的外壳程序中使用任何这些名称定义外壳程序功能。这是一件好事 -它使人们能够安全地编写可移植脚本。这些是基本命令,有经验的脚本编写者可以通过这些命令在他或她的环境中建立安全可靠的立足点。建议侵入此名称空间。

但是,如果您确实想入侵它,可以使用进行移植alias。Shell 扩展的顺序使此变通办法。因为在alias读取命令时set会展开,所以您在定义中替换名称的任何内容都将正确扩展,因此很可能不应将其扩展为这些名称之一。

因此,您可以执行以下操作:

alias set=./set

...就可以了。


3

问题是set内置的shell,最好的解决方案是为可执行程序使用其他名称

顺带提一下,上周,我问了一个问题,该如何运行系统命令而不是使用相同名称的shell buildins,我接受的解决方案是通过env以下命令运行命令:

env set 2 3

对于这种特殊情况,您已经知道要使用的命令位于当前目录中,那么最好通过输入可执行文件的路径(.用来表示当前工作目录)直接运行该可执行文件:

./set 2 3

以上两种解决方案都是与外壳无关的,即,无论您使用哪个外壳,它们都将起作用。

诸如使用command内置函数之类的建议在Bash中将不起作用:这只会阻止运行Shell 函数。虽然没有记录,但我也注意到使用command也抑制了shell 关键字。但是,它对于诸如shell之类的shell 内建函数不会起到同样的作用set。据我了解,它command可以与其他shell(例如zsh)一起使用。

此外,诸如\set"set"或之类的技巧'set'对Bash内置函数不起作用-尽管它们对于运行可执行文件(而不是别名或shell 关键字)很有用。

注意:此答案最初是对Eric(已接受)答案的评论,但由于太大而无法放入评论中。推荐使用type而不添加.到PATH 的其他答案都是很好的答案。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.