getting shell command from user input and executing C program
currently working on program which recieves input command for linux shell and executing them creating child process.
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <开发者_运维百科;stdio.h>
#include <errno.h>
int main(int argc, char * argv[])
{
int pid, status;
if (argc < 2) {
printf("Usage: %s command, [arg1 [arg2]...]\n", argv[0]);
return EXIT_FAILURE;
}
printf("Starting %s...\n", argv[1]);
pid = fork();
if (pid == 0) {
execvp(argv[1], &argv[1]);
perror("execvp");
return EXIT_FAILURE; // Never get there normally
} else {
if (wait(&status) == -1) {
perror("wait");
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
Works with input like ./program command arg
but needed to receive various commands with args for example : ./program command arg command arg .....
Any suggestions?
A shell is a complex piece of software, I recently had to implement one for an Operating Systems class and it was difficult; and we only had to control one command per input (though we did also have to implement I/O redirection, and piping, and had to do path searching manually then execute with execv()
).
The problem you are going to have lies in that there really isn't any way to tell if the next arg string in the array of command line parameters is a command or argument to a previous command. The only ways that you can differentiate commands and their args is if you know that it will alternate command arg command arg ...
, or have some other standardized number of arguments per command (which isn't very useful) or have a deliminator between commands like a semicolon: command arg; command arg arg arg; ...
In the case that you know it will alternate then you can just loop through the args like so:
for(int i = 1; i < argc; i += 2)
{
//command is argv[i], arg is argv[i + 1]
}
A better way to do this, would be instead of using command line parameters create an input prompt then process one command per line, just like normal shell usage.
You don't actually say what your problem is, but my guess is that you are having problems working out how each forked process will consume the parameters.
I guess what you do is that each time you fork you need to advance the argv
pointer to the next command/arg pair. This forking loop terminates when the command is the zero terminator.
I hope I have understood your question because you haven't actually stated what aspect of this problem you are stuck on.
argc
tells you the size of argv
You'd need to extract them from argv
using that info.
Note that this doesn't solve the problem of commands with different numbers of args.
Edit for that reason in reply to comments:
You can look at getopt()
which would allow you to do this:
./program -c "command arg1 arg2" -c "command arg1" ...
The problem is you need to be able to differentiate between your command/arg sets. getopt()
would at least get you half way there, then you just need to parse each set. Though it's really overkill since that's your only input type. Iterating through argv
would be just as easy in this case.
Another option would be to separate them with a delimiter:
./program command arg1, command arg1 arg2, ...
You'd need to iterate through argv
and look for the comma to know a command/arg set was complete. Or concat all of argv into a string and use strtok()
. Kinda ugly IMHO but doable.
I think the question here is parsing argv.
Here is a dummy logical flow:
for(i = 1; i < argc; i++)
{
isCommand = CheckCmd(argv[i]); /* check if argv[i] is a command */
if (isCommand)
{
for(; i < argc; i++)
{
isCommand = CheckCmd(argv[i]); /* check if argv[i] is a command */
if (isNotCommand)
{
PushOption(argv[i]); /* save options */
} else
{
/* Get Command and options from stack */
/* execute command with fork/execv */
}
}
}
}
The only thing you need here is to realize CheckCmd and PushOption/PopOption.
精彩评论