Ich habe Schwierigkeiten, eine Shell mit Pipelines für die Klasse zu implementieren.UNIX-Pipes auf C-Block auf lesen
typedef struct {
char** cmd;
int in[2];
int out[2];
} cmdio;
cmdio cmds[MAX_PIPE + 1];
Befehle in der Pipeline werden in cmds
gelesen und gespeichert.
cmdio[i].in
ist das Paar von Dateideskriptoren der von pipe()
zurückgegebenen Eingabe-Pipe. Für den ersten Befehl, der von der Terminaleingabe liest, ist es nur {fileno (stdin), -1}. cmdin[i].out
ist für die Ausgabe Rohr/Terminal-Ausgang ähnlich. cmdio[i].in
ist das gleiche wie cmd[i-1].out
. Zum Beispiel:
$ ls -l | sort | wc
CMD: ls -l
IN: 0 -1
OUT: 3 4
CMD: sort
IN: 3 4
OUT: 5 6
CMD: wc
IN: 5 6
OUT: -1 1
Wir geben jeden Befehl zu process_command, die eine Reihe von Dingen tun:
for (cmdi = 0; cmds[cmdi].cmd != NULL; cmdi++) {
process_command(&cmds[cmdi]);
}
Jetzt, nach innen process_command:
if (!(pid_fork = fork())) {
dup2(cmd->in[0], fileno(stdin));
dup2(cmd->out[1], fileno(stdout));
if (cmd->in[1] >= 0) {
if (close(cmd->in[1])) {
perror(NULL);
}
}
if (cmd->out[0] >= 0) {
if (close(cmd->out[0])) {
perror(NULL);
}
}
execvp(cmd->cmd[0], cmd->cmd);
exit(-1);
}
Das Problem ist, dass die von der Lese Rohrblöcke für immer:
COMMAND $ ls | wc
Created pipe, in: 5 out: 6
Foreground pid: 9042, command: ls, Exited, info: 0
[blocked running read() within wc]
Wird anstelle des Prozesses mit execvp
Austausch ich dies nur tun:
if (!(pid_fork = fork())) {
dup2(cmd->in[0], fileno(stdin));
dup2(cmd->out[1], fileno(stdout));
if (cmd->in[1] >= 0) {
if (close(cmd->in[1])) {
perror(NULL);
}
}
if (cmd->out[0] >= 0) {
if (close(cmd->out[0])) {
perror(NULL);
}
}
char buf[6];
read(fileno(stdin), buf, 5);
buf[5] = '\0';
printf("%s\n", buf);
exit(0);
}
Es arbeiten passiert:
COMMAND $ cmd1 | cmd2 | cmd3 | cmd4 | cmd5
Pipe creada, in: 11 out: 12
Pipe creada, in: 13 out: 14
Pipe creada, in: 15 out: 16
Pipe creada, in: 17 out: 18
hola!
Foreground pid: 9251, command: cmd1, Exited, info: 0
Foreground pid: 9252, command: cmd2, Exited, info: 0
Foreground pid: 9253, command: cmd3, Exited, info: 0
Foreground pid: 9254, command: cmd4, Exited, info: 0
hola!
Foreground pid: 9255, command: cmd5, Exited, info: 0
Was könnte das Problem?
Hum, funktioniert nicht: \ Es ist immer noch das gleiche, außer stdin/stdout wird geschlossen, bevor der Befehl ausgeführt wird, so zum Beispiel 'cat' scheitert mit' cat: stdin: Bad file descriptor'. Aber selbst wenn ich es vermeide, stdin/out zu schließen, ist das Verhalten das gleiche wie zuvor. Soweit ich verstehe, beziehen sich sowohl 'cmd -> (in | out) [(0 | 1)]' auf die gleichen zugrunde liegenden Dateien wie 'fileno (std (in | out)', nicht wahr? –
Nun Jede Pipe hat einen Lesedeskriptor und einen Schreibdeskriptor.Wie ich es verstehe, haben Sie zwei Pipes zwischen Eltern und Kind (oder zwischen den beiden Kindern).In jedem Child-Prozess wollen Sie nur eine 'dup2()' des Lese-Endes einer Pipe auf 'stdin' öffnen und nur die' dup2() 'des Schreib-Endes der anderen Pipe auf' stdout' öffnen; alle vier der ursprünglichen Enden der Pfeife sollten geschlossen sein (was Leute überrascht). Ich bin mir nicht sicher, ob wir genug vom Code haben, um zu sagen, was sonst noch schief läuft. –
Dank Jonathan, ich habe nicht beide Enden der Rohre von den Eltern geschlossen, wie du gesagt hast. Danke vielmals! –