简体   繁体   English

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

[英]Checking if input is a valid shell command, Linux

I'm developing a simple shell for an assignment. 我正在为任务开发一个简单的外壳。 I read a command entered by the user, tokenize it, fork() , then in the child process use execvp() to execute the command in the background. 我读取了用户输入的命令,将其标记为fork() ,然后在子进程中使用execvp()在后台执行该命令。

The problem is I need to implement a history feature that records valid commands. 问题是我需要实现一个记录有效命令的历史记录功能。 The only way I know to check if the string the user enters is a valid command is to check if execvp() returns -1. 我知道检查用户输入的字符串是否有效的唯一方法是检查execvp()返回-1。 This is a fine way to check for an invalid command, but since the call to execvp() happens in the child process and the data structure I use for my history is copied to the child on fork() rather than shared, I can't update the history using the results of the execvp() within the child (since the history structure is a copy any changes I make won't be reflected in the parent's copy of the structure). 这是检查无效命令的一种好方法,但是由于对execvp()的调用发生在子进程中,并且我用于历史记录的数据结构被复制到fork()上的fork()而不是共享,所以我可以请使用子对象中execvp()的结果来更新历史记录(由于历史记录结构是副本,因此我所做的任何更改都不会反映在父结构的副本中)。

Is there any way I can check if execvp() would return -1 without actually calling it (ie before or after the fork)? 有什么方法可以检查execvp() 是否会返回-1而不实际调用它(即在fork之前或之后)? If I could figure out a way to do that I'd be able to verify in the parent processes whether or not execvp() will succeed and use that info to update my history data structure properly. 如果我能找到一种方法,可以在父进程中验证execvp()是否会成功,并使用该信息正确更新我的历史记录数据结构。

What you are asking for is a system call which would let you implement the classic check-before-do race condition. 您要的是一个系统调用,该调用可让您实现经典的先检查后竞赛条件。

In that error, a program verifies whether an action is possible and then performs the action, leaving open the possibility that some external event will happen just after the check which makes the action illegal. 在该错误中,程序将验证是否有可能执行某项操作,然后执行该操作,从而使检查之后的某些外部事件(使该操作非法)的可能性得以保留。

So then the action fails, even though the program checked that it was possible. 因此,即使程序检查了是否可行,操作也失败了。 This often results in chaos. 这通常会导致混乱。

You should avoid this antipattern, and the system API should help by not tempting you with system calls you would only use to get yourself into trouble. 您应该避免使用这种反模式,而系统API应该通过不诱使您陷入麻烦的系统调用来帮助您。 In this case, the system does the right thing; 在这种情况下,系统会做正确的事; there is no such API. 没有这样的API。

The parent process must eventually retrieve the exit status of the child. 父进程最终必须检索子进程的退出状态。 That is the moment you need to update (or not) the history. 那是您需要更新(或不需要)历史记录的时刻。 If a failed execvp causes the child to exit() with a failure status code, the parent will notice the failure and can react by not adding the command line to the history. 如果失败的execvp导致子进程以失败状态代码退出(),则父进程会注意到该失败,并且可以通过不向历史记录添加命令行来做出反应。


Some notes added after a bit of reflection: 经过一番思考后添加了一些注释:

  1. To retrieve the status code of the child process, the parent will call wait or waitpid . 要检索子进程的状态码,父进程将调用waitwaitpid For synchronous execution, the parent will likely do so immediately; 对于同步执行,父级可能会立即执行; for asynchronous execution, the parent will do so when it receives a SIGCHLD signal. 对于异步执行,父级在收到SIGCHLD信号时会这样做。 But it is imperative that the parent does this, to avoid zombie processes. 但是家长必须这样做,以避免僵尸进程。

  2. In the case of asynchronous execution, it is not possible to use this strategy to avoid putting invalid commands into the history, because asynchronous commands must be recorded in the history when they are started. 在异步执行的情况下,无法使用此策略来避免将无效命令放入历史记录,因为异步命令在启动时必须记录在历史记录中。 For a similar reason, Posix shells also count asynchronous execution of a command as successful, even if the command is invalid. 出于类似的原因,即使命令无效,Posix Shell也将命令的异步执行视为成功。

  3. While this exercise undoubtedly has pedagogic value (as I hope this answer demonstrates), it is actually a terrible way of doing shell history. 尽管此练习无疑具有教学法的价值(正如我希望这个答案所证明的那样),但实际上这是做壳历史的一种可怕方法。 While shell users occasionally use history to retrieve and re-execute successful commands, the history feature is much more useful to retrieve and edit an unsuccessful command. 尽管Shell用户偶尔会使用历史记录来检索和重新执行成功的命令,但是历史记录功能对于检索和编辑不成功的命令更为有用。 It's intensely annoying to not be able to make corrections from a history feature. 无法从历史记录功能进行更正,这非常烦人。 (Many Android applications exhibit precisely this annoying flaw with search history: after a search which gives you undesired results, you can retrieve the incorrect search and rerun it, but not modify it. I'm glad to say that things have improved since my first Android.) (许多Android应用程序都在搜索历史记录中确实表现出这种令人讨厌的缺陷:进行搜索后,您会得到不想要的结果,您可以检索不正确的搜索并重新运行它,但不能修改它。 Android系统。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM