* Почти * Perfect C Shell Piping
Я пишу небольшую оболочку Linux в C, и я настолько близок к тому, чтобы ее выполняли. Я беру команду у пользователя и сохраняю ее в args, помеченной пробелами. В следующем примере предположим, что args содержит следующее:
args[] = {"ls", "-l", "|", "wc"};
Моя функция принимает args, а также принимает количество труб. Я прокомментировал свой код как можно больше. Вот он:
int do_command(char **args, int pipes) {
// The number of commands to run
const int commands = pipes + 1;
int i = 0;
int pipefds[2*pipes];
for(i = 0; i < pipes; i++){
if(pipe(pipefds + i*2) < 0) {
perror("Couldn't Pipe");
exit(EXIT_FAILURE);
}
}
int pid;
int status;
int j = 0;
int k = 0;
int s = 1;
int place;
int commandStarts[10];
commandStarts[0] = 0;
// This loop sets all of the pipes to NULL
// And creates an array of where the next
// Command starts
while (args[k] != NULL){
if(!strcmp(args[k], "|")){
args[k] = NULL;
// printf("args[%d] is now NULL", k);
commandStarts[s] = k+1;
s++;
}
k++;
}
for (i = 0; i < commands; ++i) {
// place is where in args the program should
// start running when it gets to the execution
// command
place = commandStarts[i];
pid = fork();
if(pid == 0) {
//if not last command
if(i < pipes){
if(dup2(pipefds[j + 1], 1) < 0){
perror("dup2");
exit(EXIT_FAILURE);
}
}
//if not first command&& j!= 2*pipes
if(j != 0 ){
if(dup2(pipefds[j-2], 0) < 0){
perror("dup2");
exit(EXIT_FAILURE);
}
}
int q;
for(q = 0; q < 2*pipes; q++){
close(pipefds[q]);
}
// The commands are executed here,
// but it must be doing it a bit wrong
if( execvp(args[place], args) < 0 ){
perror(*args);
exit(EXIT_FAILURE);
}
}
else if(pid < 0){
perror("error");
exit(EXIT_FAILURE);
}
j+=2;
}
for(i = 0; i < 2 * pipes; i++){
close(pipefds[i]);
}
for(i = 0; i < pipes + 1; i++){
wait(&status);
}
}
Моя проблема в том, что, хотя программа работает правильно, она ведет себя странно, и я надеялся, что вы мне поможете.
Например, я запустил ls | wc, выход - ls | wc, но затем он также выводит результат простого ls прямо под ним, хотя он должен быть только wc для вывода.
В качестве другого примера, когда я пытаюсь выполнить ls -l | wc, появляется первое число wc, но затем появляется вывод ls -l, хотя он должен быть просто wc выходного файла.
Спасибо заранее!:)
Ответы
Ответ 1
Хорошо, я обнаружил одну небольшую ошибку. Это
if( execvp(args[place], args) < 0 ){
должен быть
if( execvp(args[place], args+place) < 0 ){
Ваша версия использовала аргументы для первой команды для всех остальных. Кроме этого, он работает для меня.