I am new to linux programming, and to get my bearings, I have been writing some small programs. I have already written a ls clone that will do ls, ls -l, and ls -lR. My current project is to write a simple shell. My understanding on how to do this is to loop the following: Get some input from the user and parse it into an array of cstrings, fork the program, have the child exec the user's command. I tried this, but I found that I lost i/o with the child after the exec, which make sense considering what it does. I did some reading online, I found that I need to use pipes to connect the child stdout and stdin to the parents before the exec. I did a few experiments with the pipes, but they all either crashed or didn't work, so I'm clearly missing something.
Is my understanding of what I need to do correct? Am I missing some small, but important detail? Is it even possible to connect out pipe to the parent's stdout so the child's output is automatically output to the console, or do I need to manually read the pipe and output its contents. Can you give me some examples of using pipes in this context, preferably in C++? Thanks in advance.
My code so far:
[code]
#include #include #include #include #include #include #include #include #include #include const unsigned int MAX_ARGS = 128;
using namespace std;
// Execute a parsed command line returning the command's exit code
int doit(const vector& tok)
{
if (!tok.size() || tok[0] == "") return 0;
// If user entered cd, change to specified dir. If no dir specified, change to the users home dir
else if (tok[0] == "cd")
{
if (tok.size() > 1) chdir(tok[1].c_str());
else chdir(getenv("HOME"));
return 0;
}
//Else execute the command specified by the user
if (pid_t kidpid = fork())
{
//Parent
int status = 0;
if (tok.back().at(tok.back().size() - 1) != '&')
{
waitpid(kidpid, &status, 0);
#ifdef _INSPECT_EXIT_STATUS
cout << "exit status=" << status << endl;
#endif //_INSPECT_EXIT_STATUS
}
return status;
}
//Child - execute the command
char* arglist[MAX_ARGS];
for (unsigned int x = 0; x < tok.size() && x < MAX_ARGS - 1; x++)
strcpy(arglist[x], tok[x].c_str());
arglist[tok.size()] = NULL;
execvp(tok[0].c_str(), arglist);
//Program will never reach here unless execvp failed
cerr << "execpv failed: " << strerror(errno) << endl;
exit(errno);
}
int main(int argc, char* argv[], char* envp[])
{
while (!cin.eof())
{
cout << "? ";
string temp;
getline(cin, temp);
if (temp == "exit") break;
vector<string> v;
//Break string into separate strings on whitespace
{
stringstream foo(temp);
string s;
while (foo >> s)
{
if (s[0]=='~') s = getenv("HOME") + s.substr(1);
v.push_back(s);
}
}
doit(v);
}
cout << "exit" << endl;
return 0;
}[/code]
Comments
I was wondering if you ever got your '|' '>' '<' up and running on your shell?
thnks