I am trying to make a minishell that can execute comands piped what I must use only one pipe.I use a parser with this types and functions:
typedef struct {
char * filename;
int argc;
char ** argv;
} tcommand;
typedef struct {
int ncommands;
tcommand * commands;
char * redirect_input;
char * redirect_output;
char * redirect_error;
int background;
} tline;
extern tline * tokenize(char *str);
This is my main and the code of the functions:
int main() {
char buf[1024];
int i, j;
system("clear");
printf("msh>");
while (fgets(buf, 1024, stdin)) {
line = tokenize(buf);
if (line == NULL){
continue;
}
comandos = line->commands;
ncomands = line->ncommands;
if (ncomands == 1) {
if (strcmp(comandos[0].argv[0], "exit") == 0) {
salir();
}
if (strcmp(comandos[0].argv[0], "cd") == 0) {
cd(comandos[0].argc, comandos[0].argv);
}else {
}
}else{
printf("Voy a ejecutar %d comandos\n", ncomands);
tcommand *recorrerComandos = comandos;
int argc = 0;
char **recorrerArgumentos;
for (i = 0; i < ncomands; i++){
argc = recorrerComandos[i].argc;
recorrerArgumentos = recorrerComandos[i].argv;
printf("Comando %d: %s\n",i,recorrerArgumentos[0]);
for(j=1; j < argc; j++){
printf("Argumnento %d: %s\n",j,recorrerArgumentos[j]);
}
printf("***************************************\n");
}
/*This is the call that does not work */
pipes(ncomands, comandos);
}
printf("msh>");
}
printf("\n");
return 0;
}
void proceso(int in, int out, tcommand comando) {
static int i = 0;
i++;
printf("Ejecuto comando %d\n",i);
pid_t pid;
pid = fork();
if (pid == 0) {
if (in != 0) {
dup2(in, 0);
close(in);
}
if (out != 1) {
dup2(out, 1);
close(out);
}
execvp(comando.argv[0], comando.argv);
fprintf(stderr, "Error al ejecutar el comando: %s\n", comandos[0].argv[0]);
exit(errno);
}
}
void pipes(int ncomands, tcommand * comandos) {
int i;
pid_t pid;
int in, fd[2];
in = 0;
for (i = 0; i < ncomands - 1; ++i) {
pipe(fd);
proceso(in, fd[1], comandos[i]);
close(fd[1]);
in = fd[0];
}
if (in != 0)
dup2(in, 0);
execvp(comandos[i].argv[0],comandos[i].argv);
}
If I run it and enter ls | grep hola the exit is
msh>ls | grep hola
Voy a ejecutar 2 comandos
Comando 0: ls
***************************************
Comando 1: grep
Argumnento 1: hola
***************************************
Ejecuto comando 1
And I do not understand where is the error that I made. Thank you in advance
Related
I've written code for a shell that we call opsh (the OPen SHell).
Now my friend found an issue about backslash preceeded characters that don't behave as expected.
Example
opsh does not seem to pass on the -character to echo.
In opsh:
$
$echo "TEXT\n"
TEXTn
$
whereas in ksh:
$
$echo "TEXT\n"
TEXT
I don't know how to do it. In my code I just use a pipeline for the commands (you may look at the entire code in the repo) where the relevant code looks as follows
int run_cmd(char *cmd, bool background) {
char buffer[2];
buffer[0] = '|';
buffer[1] = '\0';
struct str_list *chunks = list_split(cmd, buffer);
struct pipeline *pipe = malloc(chunks->pipes * sizeof *pipe);
if (pipe == NULL) {
fprintf(stderr, "malloc failed!\n");
}
int i = 0;
for (i = 0; i < chunks->pipes; i++) {
pipe[i].data = malloc(sizeof(char **) * BUFFER_SIZE * chunks[i].size);
if (pipe[i].data == NULL) {
fprintf(stderr, "malloc failed!\n");
}
int j = 0;
pipe[i].size = chunks[i].size;
for (j = 0; j < chunks[i].size; j++) {
if (chunks[i].argv[j] == NULL) {
chunks[i].argv[j] = '\0';
break;
}
pipe[i].option = malloc(sizeof(int) * 10);
if (pipe[i].option == NULL) {
fprintf(stderr, "malloc failed!\n");
}
pipe[i].data[j] = strdup(chunks[i].argv[j]);
if (pipe[i].data[j] == NULL) {
perror("strdup");
exit(EXIT_FAILURE);
}
* pipe[i].option = * chunks[i].option;
}
pipe[i].data[j] = '\0';
}
int status = execute_pipeline(chunks->pipes, pipe, background);
return status;
}
int execute_pipeline(int n, struct pipeline *pipe, bool background) {
// background = false;
int status = 0;
pid_t pid = -2;
if (n > -1)
pid = fork();
if (pid < 0) {
perror("fork failed");
return -1;
}
/* If we are the child process, then go execute the string.*/
if (pid == 0) {
/* spawn(cmd);*/
fork_pipeline(n, pipe);
}
/*
* We are the parent process.
* Wait for the child to complete.
*/
if (!background) {
while (((pid = waitpid(pid, &status, 0)) < 0) && (errno == EINTR));
fprintf(stderr, "%d: executed\n", (int) pid);
}
if (pid < 0) {
fprintf(stderr, "Error from waitpid: %s", strerror(errno));
return -1;
}
if (WIFSIGNALED(status)) {
fprintf(stderr, "pid %ld: killed by signal %d\n",
(long) pid, WTERMSIG(status));
return -1;
}
return WEXITSTATUS(status);
}
/* Helper function that forks pipes */
void fork_pipeline(int n, struct pipeline *structpipeline) {
int i;
int in = 0;
int fd[2];
for (i = 0; i < n - 1; ++i) {
if (pipe(fd) == -1) {
err_syserr("Failed creating pipe");
}
spawn_pipe(in, fd[1], structpipeline + i);
close(fd[1]);
in = fd[0];
}
if (dup2(in, 0) < 0) {
err_syserr("dup2() failed on stdin for %s: ", structpipeline[i].data[0]);
}
if (strstr(structpipeline[i].data[0], "=")) {
/* do nothing for now, handle in parser instead... */
}
else {
fprintf(stderr, "%d: executing %s\n", (int) getpid(), structpipeline[i].data[0]);
//fprintf(stderr, "\n");
if (* (structpipeline[i].option) == 1) { /* output redirection */
int length = structpipeline[i].size;
char *filename = structpipeline->data[length - 1];
for (int k = length - 2; k < length; k++)
structpipeline->data[k] = '\0';
fd[1] = open(filename, O_WRONLY | O_CREAT, 0666);
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
} /* TODO: input redirection */
execvp(structpipeline[i].data[0], structpipeline[i].data);
err_syserr("failed to execute %s: ", structpipeline[i].data[0]);
}
}
I have a problem with pipes. My program is a Shell program in C. I want to execute for example ls | wc, but what I get after running is:
ls: cannot access |: no such file or directory ls: cannot access wc: no such file or directory.
What am I doing wrong?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#define MAX_CMD_LENGTH 100
#define MAX_NUM_PARAMS 10
int parsecmd(char* cmd, char** params) { //split cmd into array of params
int i,n=-1;
for(i=0; i<MAX_NUM_PARAMS; i++) {
params[i] = strsep(&cmd, " ");
n++;
if(params[i] == NULL) break;
}
return(n);
};
int executecmd(char** params) {
pid_t pid = fork(); //fork process
if (pid == -1) { //error
char *error = strerror(errno);
printf("error fork!!\n");
return 1;
} else if (pid == 0) { // child process
execvp(params[0], params); //exec cmd
char *error = strerror(errno);
printf("unknown command\n");
return 0;
} else { // parent process
int childstatus;
waitpid(pid, &childstatus, 0);
return 1;
}
};
int execpipe (char ** argv1, char ** argv2) {
int fds[2];
pipe(fds);
int i;
pid_t pid = fork();
for (i=0; i<2; i++) {
if (pid == -1) { //error
char *error = strerror(errno);
printf("error fork!!\n");
return 1;
} else
if (pid == 0) {
if(i ==0){
close(fds[1]);
dup2(fds[0], 0);
close(fds[0]);
execvp(argv1[0], argv1);
char *error = strerror(errno);
printf("unknown command\n");
return 0;
} else if(i == 1) {
close(fds[0]);
dup2(fds[1], 1);
close(fds[1]);
execvp(argv2[0], argv2);
char *error = strerror(errno);
printf("unknown command\n");
return 0;
}
} else { // parent process
int childstatus;
waitpid(pid, &childstatus, 0);
return 1;
}
} // end for
};
int main() {
char cmd[MAX_CMD_LENGTH+1];
char * params[MAX_NUM_PARAMS+1];
char * argv1[MAX_NUM_PARAMS+1];
char * argv2[MAX_NUM_PARAMS+1];
int k, y, x;
int f = 1;
while(1) {
printf("$"); //prompt
if(fgets(cmd, sizeof(cmd), stdin) == NULL) break; //read command, ctrl+D exit
if(cmd[strlen(cmd)-1] == '\n') { //remove newline char
cmd[strlen(cmd)-1] = '\0';
}
int j=parsecmd(cmd, params); //split cmd into array of params
if (strcmp(params[0], "exit") == 0) break; //exit
for (k=0; k <j; k++) { //elegxos gia uparksi pipes
if (strcmp(params[k], "|") == 0) {
f = 0; y = k;
printf("pipe found\n");
}
}
if (f==0) {
for (x=0; x<k; x++) {
argv1[x]=params[x];
}
int z = 0;
for (x=k+1; x< j; x++) {
argv2[z]=params[x];
z++;
}
if (execpipe(argv1, argv2) == 0) break;
} else if (f==1) {
if (executecmd(params) == 0) break;
}
} // end while
return 0;
}
Updated your code with following corrections.
Removed for() loop that iterated two times after fork() call.
Removed incorrect close of pipe FDs after dup2 calls for both parent and child processes.
Aligned the command that needed to be run as per the file descriptors that were duplicated in dup2() calls for parent and child. Basically I needed to swap execvp(argv2[0], argv2) and execvp(argv1[0], argv1) calls.
Added a break; statement in the for loop that searched for pipe character.
The updated code is as below.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAX_CMD_LENGTH 100
#define MAX_NUM_PARAMS 10
int parsecmd(char* cmd, char** params) { //split cmd into array of params
int i,n=-1;
for(i=0; i<MAX_NUM_PARAMS; i++) {
params[i] = strsep(&cmd, " ");
n++;
if(params[i] == NULL) break;
}
return(n);
};
int executecmd(char** params) {
pid_t pid = fork(); //fork process
if (pid == -1) { //error
char *error = strerror(errno);
printf("error fork!!\n");
return 1;
} else if (pid == 0) { // child process
execvp(params[0], params); //exec cmd
char *error = strerror(errno);
printf("unknown command\n");
return 0;
} else { // parent process
int childstatus;
waitpid(pid, &childstatus, 0);
return 1;
}
};
int execpipe (char ** argv1, char ** argv2) {
int fds[2];
pipe(fds);
int i;
pid_t pid = fork();
if (pid == -1) { //error
char *error = strerror(errno);
printf("error fork!!\n");
return 1;
}
if (pid == 0) { // child process
close(fds[1]);
dup2(fds[0], 0);
//close(fds[0]);
execvp(argv2[0], argv2); // run command AFTER pipe character in userinput
char *error = strerror(errno);
printf("unknown command\n");
return 0;
} else { // parent process
close(fds[0]);
dup2(fds[1], 1);
//close(fds[1]);
execvp(argv1[0], argv1); // run command BEFORE pipe character in userinput
char *error = strerror(errno);
printf("unknown command\n");
return 0;
}
};
int main() {
char cmd[MAX_CMD_LENGTH+1];
char * params[MAX_NUM_PARAMS+1];
char * argv1[MAX_NUM_PARAMS+1] = {0};
char * argv2[MAX_NUM_PARAMS+1] = {0};
int k, y, x;
int f = 1;
while(1) {
printf("$"); //prompt
if(fgets(cmd, sizeof(cmd), stdin) == NULL) break; //read command, ctrl+D exit
if(cmd[strlen(cmd)-1] == '\n') { //remove newline char
cmd[strlen(cmd)-1] = '\0';
}
int j=parsecmd(cmd, params); //split cmd into array of params
if (strcmp(params[0], "exit") == 0) break; //exit
for (k=0; k <j; k++) { //elegxos gia uparksi pipes
if (strcmp(params[k], "|") == 0) {
f = 0; y = k;
printf("pipe found\n");
break;
}
}
if (f==0) {
for (x=0; x<k; x++) {
argv1[x]=params[x];
}
int z = 0;
for (x=k+1; x< j; x++) {
argv2[z]=params[x];
z++;
}
if (execpipe(argv1, argv2) == 0) break;
} else if (f==1) {
if (executecmd(params) == 0) break;
}
} // end while
return 0;
}
If you are interested only in changes I made, here is the diff between your code and the above updated code:
--- original.c
+++ updated.c
## -4,6 +4,7 ##
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
+#include <sys/wait.h>
#define MAX_CMD_LENGTH 100
## -43,44 +44,36 ##
pipe(fds);
int i;
pid_t pid = fork();
- for (i=0; i<2; i++) {
if (pid == -1) { //error
char *error = strerror(errno);
printf("error fork!!\n");
return 1;
- } else
- if (pid == 0) {
- if(i ==0){
+ }
+ if (pid == 0) { // child process
close(fds[1]);
dup2(fds[0], 0);
- close(fds[0]);
- execvp(argv1[0], argv1);
+ //close(fds[0]);
+ execvp(argv2[0], argv2); // run command AFTER pipe character in userinput
char *error = strerror(errno);
printf("unknown command\n");
return 0;
- } else if(i == 1) {
+ } else { // parent process
close(fds[0]);
dup2(fds[1], 1);
- close(fds[1]);
- execvp(argv2[0], argv2);
+ //close(fds[1]);
+ execvp(argv1[0], argv1); // run command BEFORE pipe character in userinput
char *error = strerror(errno);
printf("unknown command\n");
return 0;
}
- } else { // parent process
- int childstatus;
- waitpid(pid, &childstatus, 0);
- return 1;
- }
- } // end for
};
int main() {
char cmd[MAX_CMD_LENGTH+1];
char * params[MAX_NUM_PARAMS+1];
- char * argv1[MAX_NUM_PARAMS+1];
- char * argv2[MAX_NUM_PARAMS+1];
+ char * argv1[MAX_NUM_PARAMS+1] = {0};
+ char * argv2[MAX_NUM_PARAMS+1] = {0};
int k, y, x;
int f = 1;
while(1) {
## -95,6 +88,7 ##
if (strcmp(params[k], "|") == 0) {
f = 0; y = k;
printf("pipe found\n");
+ break;
}
}
if (f==0) {
execv* procedure doesn't interpret shell script string. It merely starts an executable file and passes an array of arguments to it. Thus, it cannot organize a pipeline.
If you need "normal" shell command execution, you may want to use system(char*) procedure instead of execvp.
Otherwise, if you need to do the pipes yourself, you may want to parse the string with '|' special characters and use pipe(), fork() and I/O redirection. Like here How to run a command using pipe?
int shell (int argc, char *argv[]) {
char *s = malloc(INPUT_STRING_SIZE+1); /* user input string */
tok_t *t; /* tokens parsed from input */
int lineNum = 0;
int fundex = -1;
pid_t pid = getpid(); /* get current processes PID */
pid_t ppid = getppid(); /* get parents PID */
pid_t cpid, tcpid, cpgid;
init_shell();
printf("%s running as PID %d under %d\n",argv[0],pid,ppid);
lineNum=0;
const int BUF_SIZE = 200;
char buf[BUF_SIZE];
getcwd(buf, BUF_SIZE);
fprintf(stdout, "%d %s: ", lineNum++, buf);
while ((s = freadln(stdin))){
char *ptrA, *ptrB;
ptrA = strstr(s, "<");
ptrB = strstr(s, ">");
if (ptrA) {
*ptrA = '\0';
ptrA++;
}
if (ptrB) {
*ptrB = '\0';
ptrB++;
}
if (ptrA && ptrB) {
} else if (ptrA) {
} else if (ptrB) {
size_t ln = strlen(ptrB) - 1;
if (ptrB[ln] == '\n') // get rid of the trailing newline
ptrB[ln] = '\0';
int newfd; /* new file descriptor */
if ((newfd = open(ptrB, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR|S_IXUSR)) < 0) {
perror("Can't open outfile file\n"); /* open failed */
exit(1);
}
printf("newfd: %d\n", newfd);
dup2(newfd, 1);
printf("Here\n");
}
printf("%s\n", s);
t = getToks(s); /* break the line into tokens */
fundex = lookup(t[0]); /* Is first token a shell literal */
if(fundex >= 0) {
cmd_table[fundex].fun(&t[1]);
} else {
char *bin;
if (get_binary(t[0], &bin) == 0) {
t[0] = bin;
}
pid_t child_pid = fork();
int exit_code;
if (child_pid == 0) {
execv(t[0], &t[0]);
} else {
wait(&exit_code);
}
}
getcwd(buf, BUF_SIZE);
fprintf(stdout, "%d %s: ", lineNum++, buf);
}
return 0;
}
I test out my shell with wc shell.c>testand what happens is I get a blank line on the terminal as if it's waiting for my input. When I hit Enter, it segfaults. If I comment out the dup2 line, the shell works perfectly (but without redirection, of course). I'm on Windows using Cygwin, if that helps.
I had my dup in the wrong place. I needed to dup after I forked, but before I execv'd.
My code worked fine until I add the extra stuffs into it, like identifying and deal with cd, >, <, >> and |. Could you please check my code and see where did the error happens?
Btw the requirement of the assignment is only up to 1 pipe. And I think the problem starts somewhere from the for loop, cause I put printf right after it to check if it would print args[k], and it did but then the bug popped up and the program stopped.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
int main()
{
const int MAX_ARGS = 10;
char *token[MAX_ARGS + 1]; /*assume max number of token <=10*/
char *temp;
char line[256], command[MAX_ARGS];
char prompt[] = "sh2 % ";
pid_t pid;
int i=0, j,k, status;
printf("%s", prompt);
while (fgets(line, sizeof line, stdin) != NULL)
{
line[strlen(line)-1] = '\0'; /*get rid of \n*/
token[0] = strtok(line," ");
strcpy(command,token[0]);
temp = strtok(NULL," ");
while (temp != NULL)
{
i = i+1;
token[i] = temp;
temp = strtok(NULL," ");
}
char *args[i+2];
for (j = 0; j < (i+1); j++)
{
args[j] = token[j];
}
args[i+1] = NULL;
if (!strcmp("exit",command))
exit(0);
if (!strcmp("cd", command))
{
int success;
if (success = chdir(args[1]) <0)
{
printf("Failed to change dir.\n");
}
}
else
{
int piping = 0;
int fd;
for (k = 0; k < sizeof args; k++)
{
if (!strcmp(">",args[k]))
{
fd = open(args[k+1],O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IXUSR);
if (fd <0) { printf("Open file failed.\n");}
else
{
dup2(fd, 1);
args[k] = '\0';
fflush(stdout);
close(fd);
}
}
if (!strcmp("<", args[k]))
{
fd = open(args[k+1], O_RDONLY);
if (fd <0) {printf("Open file failed.\n");}
else
{
dup2(fd, 0);
args[k] = '\0';
close(fd);
}
}
if (!strcmp(">>", args[k]))
{
fd = open(args[k+1], O_APPEND | O_CREAT, S_IRUSR | S_IWUSR | S_IXUSR);
if (fd <0) {printf("Open file failed");}
else
{
dup2(fd,1);
args[k] = '\0';
fflush(stdout);
close(fd);
}
}
if (!strcmp("|", args[k]))
{
piping = 1;
}
} /*end for*/
if (!(piping))
{
pid = fork();
if (pid <0) {}
else if (pid == 0)
{
if ( (status = execvp(command, args)) < 0 )
{
printf("Command not found\n");
}
}
else /*parent*/
{
wait(&status);
} /*end parent*/
}/*end if not pipe*/
else /*its pipe*/
{
int pfd[2];
pipe(pfd);
fd = fork();
if (fd < 0) {}
else if (fd ==0)
{
close(pfd[1]);
dup2(pfd[0],0);
close(pfd[0]);
execvp(args[2],args[2]);
}
else /*parent*/
{
close(pfd[0]);
dup2(pfd[1],1);
close(pfd[1]);
execvp(args[0],args[0]);
}
}/*end pipe*/
} /*end outter else*/
printf("%s", prompt);
}/*end while*/
return 0;
}
for (k = 0; k < sizeof args; k++)
This is not how you iterate through args: this will go far beyond the end of the array. You want something like:
num = sizeof(args) / sizeof(*args);
for (k = 0; k < num; k++)
Alternatively, since you set the last element as NULL, you could do
for (char **arg = args; *arg; arg++)
Also note that you iterate with k until the end of the array and then use k + 1, which is very likely to cause problems.
I'm actually trying to implement a basic minishell in C. For doing that, I made a fonction which parse what the user enter in the console. I parsed it and then I would like to send the command to the console using pipes. I don't understand why my pipes are not working.
I checked the parsing and it seems to be fine, i have the right commands in parameters of the fonction.
The thing is that my pipe code is literally doing nothing and I don't understand why.
Here is my code.
Thank you in advance.
#define READ 0
#define WRITE 1
char *cmds[5] = {0};
int main() {
char *saisie = (char*)malloc(100*sizeof(char*));
char *saisie2 = (char*)malloc(100*sizeof(char*));
gets(saisie);
int ncmds = 0;
int k = 0;
char* token = (char*)malloc(100*sizeof(char*));
char* tofree;
if(*(saisie + 0) == '$'){
if(*(saisie + 2) == 'e' && *(saisie + 3) == 'x' && *(saisie + 4) == 'i' || *(saisie + 5) == 't'){
exit(0);
}
else{
int i;
for(i = 0;i<99;i++){
*(saisie2+i) = *(saisie+i+1);
}
free(saisie);
if (saisie2 != NULL) {
tofree = saisie2;
while ((token = strsep(&saisie2, "|")) != NULL){
cmds[ncmds] = token;
ncmds++;
}
free(tofree);
}
}
}
exe(cmds, ncmds);
while(wait(NULL) > 0);
return 0;
}
int exe(char *cmds[], int ncmds){
int fdin, fdout;
int fds[2];
int i;
int status;
fdin = 0;
for(i=0; i < ncmds-1; i++){
pipe(fds);
fdout = fds[WRITE];
if(fork() == 0){
if( fdin != 0 ) {
close(0);
dup(fdin);
close(fdin);
}
if( fdout != 1 ) {
close(1);
dup(fdout);
close(fdout);
}
close(fds[READ]);
const char* prog2[] = {cmds[i], "-l", 0};
execvp(cmds[i], prog2);
fprintf(stderr, "si esto se ve es un error\n");
exit(1);
}
if(fdin != 0)
close(fdin);
if(fdout != 1)
close(fdout);
fdin = fds[READ];
}
/* Ultimo comando */
fdout = 1;
if(fork() == 0) {
if( fdin != 0 ) {
close(0);
dup(fdin);
close(fdin);
}
const char* prog2[] = {cmds[i], "-l", 0};
execvp(cmds[i], prog2);
close(fds[READ]);
exit(1);
}
if(fdout!= 1)
close(fdout);
if(fdin != 0)
close(fdin);
}
}
int exe(char *cmds[], int ncmds){
int p2c[2];//pipe parent to child
int c2p[2];//pipe child to parent
int i;
int status;
int pid;
char buf[4096];
memset(buf, 0, 4096);
for(i=0; i < ncmds; i++){
pipe(p2c);
pipe(c2p);
pid = fork();
if(pid < 0) {
exit 1;
}
if(pid == 0){ //in child
close(1);
dup2(c2p[1],1); // make child write to c2p pipe instead of stdout
close(0);
dup2(p2c[0],0); // make child read from p2c pipe instead of stdin
close(p2c[1]);
close(c2p[0]);
const char* prog2[] = {cmds[i], "-l", 0};
execvp(cmds[i], prog2);
fprintf(stderr, "si esto se ve es un error\n");
exit(1);
}
//in parent
write(p2c[1], buf, strlen(buf)); //write the last output to child
close(p2c[1]);
close(c2p[1]);
memset(buf,0,4096);
if(read(c2p[0], buf, 4096) > 0){ //read output from child
if(i == ncmds -1 ){
printf("result:\n");
printf("%s\n", buf);
}
}
}
}