View Full Version : [C] Eseguire popen senza visualizzare l'output
Ciao.
Devo implementare il meccanismo delle pipe comportandosi come si comporta la shell di Linux. Ho pensato che si potesse usare la funzione popen per ogni comando da eseguire nella pipe. Il problema è che non so quale potrebbe essere un modo per eseguire un comando senza visualizzare il suo output. Cioè deve far vedere l'output solo dell'ultimo comando nella catena di comandi nella pipe e quindi degli altri no. Come posso fare?
Grazie. :)
Quello ci sono riuscito. Praticamente ho redirezionato l'STDOUT sulla struttura FILE * della pipe prima di chiamare la popen. Ora mi servirebbe capire come visualizzare l'output dell'ultimo comando (a seguito dei comandi eseguiti in precedenza).
Nessuno sa rispondere? :(
L'idea di base è questa:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
int p[2];
pid_t pid;
char *c1[] = {"ls", "-l", NULL};
char *c2[] = {"head", "-n", "1", NULL};
if (pipe(p) < 0) {
perror("pipe()");
exit(EXIT_FAILURE);
}
if ((pid = fork()) < 0) {
perror("fork()");
exit(EXIT_FAILURE);
}
if (pid == 0) {
close(p[0]);
dup2(p[1], STDOUT_FILENO);
close(p[1]);
execvp(c1[0], c1);
perror("execvp()");
_exit(EXIT_FAILURE);
}
if ((pid = fork()) < 0) {
perror("fork()");
exit(EXIT_FAILURE);
}
if (pid == 0) {
close(p[1]);
dup2(p[0], STDIN_FILENO);
close(p[0]);
execvp(c2[0], c2);
perror("execvp()");
_exit(EXIT_FAILURE);
}
close(p[0]);
close(p[1]);
wait(NULL);
wait(NULL);
return 0;
}
Ok, grazie. Ma avendo più processi da mettere in pipe come faccio ogni volta a fare quelle redirezioni? E attraverso popen come faccio a fargli avere un comportamento simile? Con popen non riesco ancora a capire quando bisogna mettere il flag r e quando quello w.
beppegrillo
05-01-2007, 19:43
Ok, grazie. Ma avendo più processi da mettere in pipe come faccio ogni volta a fare quelle redirezioni? E attraverso popen come faccio a fargli avere un comportamento simile? Con popen non riesco ancora a capire quando bisogna mettere il flag r e quando quello w.
ti consiglio di leggerti il man di pipe, visto che non mi pare tu abbia chiaro cosa sia effettivamente una pipe, popen è qualcosa al di sopra di pipe.
L'ho già letta la man di pipe. Il problema rimane. Ripeto non capisco con popen quando bisogna mettere il flag r e quando quello w. Per quanto riguarda le pipe "normali" create tramite la funzione pipe() le ho capite.
La popen() restituisce uno stream unidirezionale, in lettura (r) o in scrittura (w).
goku@nig:/tmp$ cat ptest.c && ./ptest && cat ptest.txt
#include <stdio.h>
int main(void)
{
FILE *in, *out;
char buffer[1024];
int c = 1;
in = popen("cat ptest.c", "r");
out = popen("cat >ptest.txt", "w");
while (fgets(buffer, sizeof buffer, in))
fprintf(out, "%2d: %s", c++, buffer);
pclose(in);
pclose(out);
return 0;
}
1: #include <stdio.h>
2:
3: int main(void)
4: {
5: FILE *in, *out;
6: char buffer[1024];
7: int c = 1;
8:
9: in = popen("cat ptest.c", "r");
10: out = popen("cat >ptest.txt", "w");
11: while (fgets(buffer, sizeof buffer, in))
12: fprintf(out, "%2d: %s", c++, buffer);
13: pclose(in);
14: pclose(out);
15:
16: return 0;
17: }
goku@nig:/tmp$
Ok, grazie. Però non capisco ancora una cosa. Cioè io eseguo il primo comando con popen, poi se ho lo stream è in sola lettura o in sola scrittura a me poco importa, perché come faccio a dirgli al prossimo comando che l'input si trova proprio in quello stream. Per fare questo posso eseguire una write di quello stream sullo STANDARD INPUT?
Ok, per quello che devo fare io mi hanno detto i miei prof. che la popen non va usata :) . In questo frammento di codice scritto da Qu@ker:
dup2(p[1], STDOUT_FILENO);
close(p[1]);
Prima ha redirezionato l'STDOUT su p[1] e poi ha chiuso p[1]. Non ho capito perché. Un'altra cosa. Per fare quello che devo fare io, andrebbero bene anche le fifo? Sarebbe una soluzione migliore? Grazie.
In questo frammento di codice scritto da Qu@ker:
dup2(p[1], STDOUT_FILENO);
close(p[1]);
Prima ha redirezionato l'STDOUT su p[1]
Non so cosa intendi tu con redirezionare. Dopo la chiamata a dup2(), entrambi i file descriptor si riferiscono allo stesso file aperto.
e poi ha chiuso p[1]. Non ho capito perché.
A te servono due riferimenti allo stesso file? (Per essere precisi, a te interessa che il file descriptor identificato da STDOUT_FILENO si riferisca al file in questione).
Un'altra cosa. Per fare quello che devo fare io, andrebbero bene anche le fifo? Sarebbe una soluzione migliore? Grazie.
In breve, no.
beppegrillo
07-01-2007, 16:15
Ok, per quello che devo fare io mi hanno detto i miei prof. che la popen non va usata :) . In questo frammento di codice scritto da Qu@ker:
dup2(p[1], STDOUT_FILENO);
close(p[1]);
Prima ha redirezionato l'STDOUT su p[1] e poi ha chiuso p[1]. Non ho capito perché. Un'altra cosa. Per fare quello che devo fare io, andrebbero bene anche le fifo? Sarebbe una soluzione migliore? Grazie.
E' proprio l'inverso quello che fai, altrimenti non avrebbe senso.
Redirezioni p[1] allo STDOUT, e poi chiudi p[1].
Ok, spero di aver capito. Grazie.
E se io poi voglio fare in modo che l'STDOUT mi ristampi l'output su schermo come faccio?
Trovato il modo ;)
Basta che redireziono p[0] su STDIN. Ora ho un piccolo problema (ho quasi finito :) ). Vi posto un pezzo di codice della funzione che esegue le pipe (è il ciclo che viene eseguito dal secondo comando della pipe in poi):
for(i=1; i<res; ++i){
if((pid = fork()) < 0){
perror("fork error");
exit(FORK_ERR);
}
if(pid == 0){
if(args!=NULL){
free(args);
args=NULL;
}
args=(char **)calloc(MAX_ARGS,sizeof(char *));
if(do_I_launch_parse(commands[i]) == 1)
parse(commands[i],args);
if(i==res-1){
close(p[1]);
if(dup2(p[0],STDIN_FILENO) == -1){
perror("dup error");
exit(DUP_ERR);
}
close(p[0]);
}
else{
if(dup2(p[0],STDIN_FILENO) == -1){
perror("dup error");
exit(DUP_ERR);
}
if(dup2(p[1],STDOUT_FILENO) == -1){
perror("dup error");
exit(DUP_ERR);
}
close(p[0]);
close(p[1]);
}
((args[0]==NULL) ? execlp(commands[i],commands[i],NULL) : execvp(commands[i],args));
perror("exec failed");
exit(EXEC_ERR);
}
if(pid > 0){
if (waitpid(pid,&status,0) == -1){
if(errno!=EINTR){
perror("waitpid error");
exit(WAIT_ERR);
}
else{
kill(pid,SIGTERM);
do{
if (waitpid(pid,&status,0) != -1)
break;
}while(errno==EINTR);
}
}
}
}
Il problema è che l'output viene fuori bene come dovrebbe venire, solo che non mi ritorna dal figlio e infatti la wait mi aspetta indefinitamente. Notate qualche errore?
Grazie.
Per favore, se riesco a risolvere quest'ultimo problema ho praticamente finito tutto. :)
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.