2016-09-16 7 views
0

Хорошо, ребята, есть миллиард демок, связанных с dup, dup2, fcntl, трубой и всеми видами вещей, которые замечательны, когда существует несколько процессов. Тем не менее, мне еще предстоит увидеть одну очень основную вещь, которая, я думаю, поможет объяснить поведение трубы и ее связь со стандартными и вне.Как использовать dup и dup2 для перенаправления стандартного вывода в трубу, а затем на antoher pipe, а затем обратно в стандартную версию?

Моя цель - просто (в том же процессе) перенаправить стандартный вывод через обратно обратно к стандартному выходу. Я уже выполнил это с промежуточными этапами, которые перенаправляют вывод трубы в файл или записывают в буфер ... и затем возвращают стандартный вывод туда, где он был запущен. В этот момент, конечно, я могу записать буфер обратно в stdout, но я не хочу этого делать.

Поскольку я переместил стандартный вывод в другое место в таблице файлов, я хотел бы направить вывод трубы на прямой канал в новую стандартную выходную позицию и напечатать его, как обычно.

Я чувствую, что вокруг таблицы файлов есть какой-то слой, который я не понимаю.

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <fcntl.h> 

int main() { 
    int pipeEnds_arr1[2]; 

    char str1[] = "STRING TO FEED INTO PIPE \n"; // make a string array 

    pipe(pipeEnds_arr1); 

    printf("File Descriptor for pipe ends from array\nPOSITION out 0 : %d\nPOSITION in 1 : %d\n", pipeEnds_arr1[0], pipeEnds_arr1[1]); 


    /* now my goal is to shift the input of the pipe into the position of 
    * standard output, so that the print command feeds the pipe, then I 
    * would like to redirect the other end of the pipe to standard out. 
    */ 

    int someInt = dup(1); // duplicates stdout to next available file table position 

    printf ("Some Int FD: %d\n", someInt); // print out the fd for someInt just for knowing where it is 

    /* This is the problem area. The out end of the pipe never 
    * makes it back to std out, and I see no way to do so. 
    * Stdout should be in the file table position 5, but when 
    * I dup2 the output end of the pipe into this position , 
    * I believe I am actually overwriting std out completely. 
    * But I don't want to overwrite it, i want to feed the output 
    * of the pipe into std out. I think I am fundamentally 
    * misunderstanding this issue. 
    */ 

    dup2(pipeEnds_arr1[1], 1); //put input end of pipe into std out position 
    //dup2(pipeEnds_arr1[0], 5); // this will not work 
    //and other tests I have conducted do not work 


    printf("File Descriptor for pipe ends from array\nPOSITION out 0 : %d\nPOSITION in 1 : %d\n", pipeEnds_arr1[0], pipeEnds_arr1[1]); 

    fflush(stdout); 

    close(pipeEnds_arr1[0]); 
    close(pipeEnds_arr1[1]); 

    return 0; 
} 

EDIT ********* Хорошо, что я знаю, что-то из StD берет информацию из таких команд, как Printf, а затем раутов его в буфер, который затем продувают в оболочку.

Я считаю, что должен быть способ разбить «прочитанный» или выходной конец трубы на тот же самый буфер, который затем попадает в оболочку. Я выяснил, как разбить вывод трубы на строку, а затем я могу сделать, как мне заблагорассудится. В примере кода я пост ниже, я буду первым разгромить трубу к строке, а затем открыть файл и записать строку дескриптора файла этого файла ...

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <fcntl.h> 


int main() { 
    /* Each pipe end array has to have 2 positions in it. The array 
    * position represents the two pipe ends with the 0 index 
    * position representing the output of the pipe (the place you want 
    * read your data from), and 1 index position representing the 
    * input file descriptor of the pipe (the place you want to write 
    * your data). 
    */ 
    int pipeEnds_arr1[2]; 

    char str1[] = "Hello, we are feeding this into the pipe that we are through stdout into a pipe and then reading from the pipe and then feeding that output into a file \n"; // make a string array 

    /* Here we want to actually do the pipe command. We feed it the array 
    * with the 2 positions in it which will now hold file descriptors 
    * attached to the current process which allow for input and output 
    * through the new pipe. At this point, we don't know what the 
    * exact file decriptors are, but we can look at them by printing 
    */ 

    pipe(pipeEnds_arr1); 
    printf("File Descriptor for pipe ends from array\nPOSITION out 0 : %d\nPOSITION in 1 : %d\n", pipeEnds_arr1[0], pipeEnds_arr1[1]); 

    /* now my goal is to shift the input of the pipe into the position of 
    * standard output, so that the print command feeds the pipe, then we 
    * will try to read from the pipe and redirect the output to the std 
    * or in this test case out to a file. 
    */ 

    int someInt = dup(1); // we moved what was stdout into someInt; 

    /* put the write end of the pipe in the old stdout position by 
    * using dup2 so we will print directly into the pipe 
    */ 
    dup2(pipeEnds_arr1[1], 1); 

    /* this is where id like to re-rout the pipe back to stdout but 
    * im obviously not understanding this correctly 
    */ 
    //dup2(someInt, 3); 

    /* since std out has now been replaced by the pipe write end, this 
    * printf will print into the pipe 
    */ 
    printf("%s", str1); 


    /* now we read from the pipe into a new string we make */ 
    int n; 
    char str2[strlen(str1)]; 
    n = read(pipeEnds_arr1[0], str2, sizeof(str2)-1); 
    str2[n] = 0; 

    /* open a file and then write into it from the output of the pipe 
    * that we saved into the str2 
    */ 
    int fd = open("tmp.out", O_WRONLY | O_CREAT | O_TRUNC, 0644); 
    write(fd, str2, strlen(str2)); 


    /* not sure about these last commands and their relevance */ 
    fflush(stdout); 
    close(pipeEnds_arr1[0]); 
    close(pipeEnds_arr1[1]); 
    close(fd); 

    return 0; 
} 
+0

Стандартный вывод - всегда * дескриптор файла '1'. То, что у вас есть в 'someInt', - это дескриптор, отличный от дескриптора' 1' после вашего вызова 'dup2'. Система 'dup' действительно вызывает * дубликаты * дескрипторов, не использует ссылки или ссылки или что-то в этом роде. Кроме того, вызовы 'dup' не изменяют номера дескрипторов, которые вы передаете. 'pipeEnds_arr1 [1]' не будет изменять значение (номер дескриптора) в любое время после вызова 'pipe'. –

+1

Это не может работать в любом случае. Один конец трубы предназначен для записи, другой конец для чтения. Таким образом, вы можете заменить «stdout» на конец записи в трубе, и ваша программа может писать материал в трубу (думая, что она пишет «stdout»). Но другой конец трубы не может быть напрямую подключен к исходному «stdout». Некоторая часть кода должна читать из трубы и записывать данные в исходный 'stdout'. – user3386109

+1

Это не может работать даже в теории, потому что это создаст бесконечный цикл. Подумайте об этом - вы в конечном итоге будете кормить выход из stdout обратно в себя. – kfx

ответ

2

Трубы не между файловые дескрипторы. Они находятся между процессами. Поэтому не имеет никакого смысла «перенаправлять стандарт через трубу».

Что вы можете сделать, это изменить таблицу дескриптора файла процесса так, чтобы его stdout (fd 1) являлся стороной записи в трубе. И вы можете изменить таблицу дескриптора файла другого процесса, так что некоторый файловый дескриптор, возможно, даже stdin (fd 0) является стороной чтения того же самого канала. Это позволяет передавать данные через канал между двумя процессами. (Вы можете настроить трубку между двумя fds в том же процессе, если хотите, иногда полезно, но следите за тупиковой ситуацией.)

stdout - не какая-то магическая сущность. Это только запись 1 в таблице fd, и она может ссылаться на любой «файл» в смысле Unix этого слова, в который входят обычные файлы, устройства (включая консоль и псевдотерминал, с которым связана ваша оболочка), сокеты, каналы , FIFO и что бы то ни было, что операционная система считает приемлемой для обеспечения потокового доступа.

Обычно, когда оболочка запускает утилиту командной строки, она сначала клонирует fds 0, 1 и 2 (stdin, stdout и stderr) из своих собственных fd 0, 1 и 2, которые обычно являются всеми одно и то же устройство: консоль или, чаще, в наши дни, псевдотерминал, предоставляемый графическим консольным приложением, которое вы используете. Но вы можете изменить эти назначения, например, с операторами перенаправления оболочки, операторами оболочки и некоторыми специальными файлами, предоставленными оболочкой.

Наконец, в ядре есть небольшие буферы, но ключом является слово «маленький» - буфер может содержать всего 4096 байт. Если он заполняется, попытки записи в трубу будут зависать до тех пор, пока не станет доступным пространство, которое произойдет только тогда, когда данные будут прочитаны из другой.Вот почему так легко затормозить, если тот же процесс использует обе стороны трубы: если процесс висит в ожидании опорожнения pileto, он никогда не сможет прочитать трубу.

+0

Я не совсем уверен, почему вы говорите, что трубы могут быть только между разными процессами. Я могу довольно легко разбить мой стандартный вывод на файл через трубу в том же процессе. Так как насчет подачи трубы из стандартного и использования его в качестве буфера, а затем перенаправления выходного конца трубы на стандартное исполнение? Я до сих пор не понимаю, почему этого не может быть. Я вполне уверен, что правильно перенаправил оператор печати в трубу, и поскольку труба ведет себя как буфер, я должен как-то отправить этот буфер обратно в консоль? – user6840486

+0

* «Я могу довольно легко разбить мой стандартный вывод на файл через канал в том же процессе». * Это поможет, если вы добавите этот код в вопрос @ user6840486. – user3386109

+0

К сожалению, я немного новичок в этом. Как мне добавить этот код? Должен ли я публиковать его как редактирование или добавлять его в другое место? @ User3386109 – user6840486

 Смежные вопросы

  • Нет связанных вопросов^_^