检查输入是否是有效的shell命令,Linux

时间:2016-02-15 05:12:33

标签: c linux shell concurrency fork

我正在为一项任务开发一个简单的shell。我读取了用户输入的命令,将其标记为fork(),然后在子进程中使用execvp()在后​​台执行命令。

问题是我需要实现记录有效命令的历史记录功能。我知道检查用户输入的字符串是否有效的唯一方法是检查execvp()是否返回-1。这是检查无效命令的好方法,但由于对execvp()的调用发生在子进程中,我用于历史记录的数据结构被复制到fork()上的子进程而不是共享,我无法使用子内execvp()的结果更新历史记录(因为历史结构是副本,我所做的任何更改都不会反映在父结构的副本中)。

有没有什么方法可以检查execvp() 是否返回-1而没有实际调用它(即在fork之前或之后)?如果我能找到一种方法,我将能够在父进程中验证execvp()是否成功并使用该信息来正确更新我的历史数据结构。

1 个答案:

答案 0 :(得分:3)

您要求的是一个系统调用,它可以让您实现经典的先接后退竞赛条件。

在该错误中,程序会验证某个操作是否可行然后执行操作,从而在检查之后发生某些外部事件的可能性,这会使操作非法。

然后,即使程序检查到可能,操作也会失败。这通常会导致混乱。

你应该避免使用这种反模式,并且系统API应该有助于不用你只会用来让你自己陷入麻烦的系统调用来诱惑你。在这种情况下,系统做正确的事情;没有这样的API。

父进程最终必须检索子进程的退出状态。那是您需要更新(或不更新)历史记录的那一刻。如果失败的execvp导致子进程使用失败状态代码退出(),则父进程将注意到失败,并且可以通过不将命令行添加到历史记录来做出反应。

经过一些反思后添加了一些注意事项:

  1. 要检索子流程的状态代码,家长会调用waitwaitpid。对于同步执行,父母可能会立即执行;对于异步执行,父节点在收到SIGCHLD信号时会这样做。但是父母必须这样做,以避免僵尸进程。

  2. 在异步执行的情况下,不可能使用此策略来避免将无效命令放入历史记录中,因为异步命令必须在启动时记录在历史记录中。出于类似的原因,即使命令无效,Posix shell也会将命令的异步执行计为成功。

  3. 虽然这个练习无疑具有教学价值(我希望这个答案能够证明),但它实际上是一种做壳历史的可怕方法。虽然shell用户偶尔会使用历史记录来检索和重新执行成功的命令,但历史记录功能对于检索和编辑不成功的命令更有用。无法通过历史记录功能进行更正非常烦人。 (许多Android应用程序恰好展现了搜索历史中令人讨厌的缺陷:在搜索结果为您提供不需要的结果后,您可以检索错误的搜索并重新运行,但不能修改它。我很高兴地说事情已经改善了我的第一个Android。)