argv = {'/usr/bin/grep', '/usr/bin/grep', '-ri', 'test', '.', 0}
pid_t pid = fork();
if (pid == 0) {
execv(argv[0], argv);
exit(0);
}
else {
wait(NULL);
}
This is what I have for my code. I am simply trying to get the grep command to run. The problem I run into is that it thinks the second /usr/bin/grep is the search pattern.
I have tried to change the argv array to only contain one /usr/bin/grep, but that errors out and does not run the grep. Any help?
execv takes the command as the first parameter so you want "usr/bin/grep" not argv[0] which is the program you are running. Also remove the first parameter from argv.
I would also check that grep is in /usr/bin it's often in /bin.
Related
What I'm trying to achieve is to open a new terminal from a C/C++ program and run vim. I'm doing this by forking and execing "xterm -e vim [fname]". Try as I might, I can't seem to get xterm to understand what it is I want it to do.
Below is the relevant code segment:
int pid = fork();
if (pid){
//parent
int retstat;
waitpid (pid, &retstat, 0);
}else{
//child
char* ifname_cchararr = (char*)malloc(ifname.length() + 1);
strcpy (ifname_cchararr, ifname.c_str());
char* const argv[4] = {"-e", "vim", ifname_cchararr, NULL};
// std::cout << ifname_cchararr<<std::endl;
execvp ("xterm", argv);
}
Running the program results in xterm complaining:
-e : Explicit shell already was /usr/bin/vim
-e : bad command line option "testfile"
I get the feeling I've messed up argc somehow, but I'm confused, because running the following in an xterm window:
xterm -e vim testfile
works perfectly fine.
Please enlighten me!
You forgot to add xterm as first argument in argv. It may seems a bit weird, that you have to add the program-name to argv, since you already tell execvp which program you're calling, but thats how it is. For more information to why, see this recently asked question on Unix & Linux: Why does argv include the program name
int main(void)
{
execl("echo", "test");
return 0;
}
I want to execute command echo test with execl
Why ? Because i can't use system() i have some reasons
What is wrong ?
The execl function does not look up commands on your PATH like a shell would, so you need to provide the full path to echo (or else provide a relative path from your current working directory, I think). Also, the first arg in the args list should be the filename of the executable, and the last arg should be NULL so that execl can figure out how many args you are trying to pass.
This works for me:
#include <unistd.h>
int main(void)
{
execl("/bin/echo", "/bin/echo", "test", NULL);
return 0;
}
You can run which echo to find out where echo is located on your system; it might be different from mine and you would have to edit the code.
There are a few different strange results that result from different types of input. First off, I'm building a simple linux shell, and below I show some example i/o
$
$
$
$ ls -l /
$ $ exit
so the first thing you probably notice is the double $. This happens whenever I have entered something into the prompt and not simply left it blank. Second, it appears to have exited properly, as it returns control back to my terminal... or does it? I really don't know, but as I'm in my terminal, if I simply press enter, this pops up in my terminal.
finn-and-jake#CandyKingom:~/Desktop/OS/hw2$ terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::at
I'm not 100% what's causing this or how to fix it, but I have a hunch that it has something to do with fork, and I believe that's also what's causing my extra $. There's also another issue with when I put input in as I did above, but with some empty input between the initial and the exit, which results in the program not completely closing out. An example is provided below.
$
$
$ ls -l /
$ $
$
$
$
$
$
$
$ exit
$ exit
and finally, there's another issue that I'm not sure what's causing it where the program runs in an infinite loop I can't force quit out of and it crashes my operating system (Ubuntu 14.04)
In an attempt to keep the code minimal, I'm only including the method that I suspect to be the cause of this. If any more than that is requested I will include it in an edit.
void Shell::interpreteInput() {
if (commandQueue.empty()) {
return;
};
if (commandQueue.at(0) == "exit") {
exit = true;
return;
};
pid_t pid = fork();
if (pid < 0) {
cerr << "Fork unsuccessful\n";
return;
};
if (commandQueue.size() >= 3 && commandQueue.at(commandQueue.size() - 2) == ">") {
//commandQueue.at(commandQueue.size() - 1) is fileName open
//commandQueue.at(0) is name of program to run exec
//remaining substrings are args
};
//commandQueue.at(0) is name of program to run exec
// remaining substrings are args
};
Edit (response to first question in comments): In the child process, execute the given program, passing it the given arguments (if any). If the program is a bare name (i.e., it does not contain any slashes), search the PATH for the executable. If the line has form 1 (my fourth if statement) —where the output is to be redirected—open (create or overwrite) a file with the given path, and redirect the program’s output to that file. (See detailed instructions below.)
• If output is to be redirected but the file cannot be opened, display an error message and return to Step 1.
• If the given program cannot be executed (exec fails), display an error message and return to Step 1.
After fork(), there is a check for a fork error, but otherwise both parent and child process do the same thing afterwards. You probably want to diverge code paths: parent does one thing and child does another.
Traditionally, a shell parent process waits for the child process to complete, unless there is an & indicating that the parent does not wait. The child then scoops together the command pipe line and exec's the command(s).
You need to make sure you're using a function like waitpid() or one of the related wait functions in the parent process. When fork() returns successfully (not -1), there are two processes running. The parent process will return the actual PID of the child process. The child process will get a return value of 0. So you need code like this:
pid_t pid = fork();
if (pid == -1) {
// handle error
} else if (pid == 0) {
// do child process stuff
} else {
// do parent process stuff
int status, rc;
do {
rc = waitpid(pid, &status, 0);
// handle rc value from waitpid
} while (!WIFEXITED(status));
}
So I am trying to execute wget in a separate child process which I am duplicating with fork as follows:
int child;
pid_t child = fork();
if ( child == 0 ) { // no errors
bool done = false; // set to false
while (!done) { // while not true do
execl("wget", "someurl", NULL);
done = true; // since dl finished
}
cout << "DL Finished\n"; // to see if child was successful
}
else if ( child != 0 ) { // errors
Any apparent errors that you can point out in this code? If it matters, this is inside a void function that I am calling in main what is happening is that it is not downloading and it displays "DL Finished", but does not execute wget - then terminal takes over.
This is executed on Ubuntu 12.04.2 LTS. I have previously inside the same void function used child to execute "ls" which works properly, that is with me telling it the whole path of ls (/bin/ls). I read that not providing the full path will make it search for the command, which is what I want.
I read that not providing the full path will make it search for the
command
That happens for execlp. Also, by convention the first argument should be the name of the executable. So you could try:
execlp("wget", "wget", "someurl", NULL);
^ ^^^^^
As a side note, your while (!done) is wrong. That's not how you wait for a program to finish. In fact, once you call exec the while is gone: another process "replaces" your own. So you can think of it "exec is a function that doesn't return". The standard way is to wait(2) in the parent until the child dies.
As a second side note, if all you want is to wget something and wait until the wget is done, the system(3) is possibly more appropriate:
system("wget someurl");
The arguments you pass to execl are what will be the argv array to the new process main function. And as you know the first entry in argv is the program name itself.
So what you need to do is:
execlp("wget", "wget", "someurl", NULL);
Also, if all went well the exec family of function does not return, so any code after the exec call will not run.
I have
#!/bin/sh
func1()
{
echo "This is func1 from shell script"
}
func2()
{
echo "This is func2 from shell script"
}
I want to call func1 and func2 from a C program. Can I do that ?
This is unlikely to be a good idea, but I suppose you could write something like this:
if (! fork()) { // TODO fork can return -1 on error; should check for that
execl("/bin/sh", "-c", ". FILE && func1", (char *)NULL);
// TODO should check to make sure execlp successfully replaced the process
}
where FILE is the name of the .sh file that defines func1. The above will spawn a child process, and replace that child process with an instance of Bash (or whatever your shell is) with the arguments -c (meaning "the script to run is the next argument") and . FILE && func1 (which is the script; it means "run the commands in FILE, and if that succeeds, then run the command func1").
For more information:
about fork
about execl
about .
A little simpler than using fork / exec is the stdlib "system" command.
See man 3 system.
Assume your bash functions are in file "/tmp/scripts.sh" ...
system("bash -c \". /tmp/scripts.sh ; func1 ; func2\"");
If you want to recive the exit code of executing script, you should use system, else use vfork + exec*