«tee», подобный программному api в UNIX

#c #unix #io

#c #unix #io

Вопрос:

Я хочу иметь что-то вроде этого

 $> ps -ax | tee -a processes.txt
  

В среде программирования UNIX C, что означает не с помощью сценариев оболочки.

В принципе, существует ли API, чтобы я мог подключаться к STDIN и / или STDOUT, чтобы я мог автоматически записывать все, что появляется в командной строке, вплоть до файла. Представьте, что процесс переднего плана взаимодействует с пользователем и отвечает некоторым выводом на терминал. Я хочу, чтобы все отображалось в терминале также в файле для последующего изучения.

Я бы представил что-то столь же волшебное, как это:

 tee(STDIN, "append", logFile);
  

Спасибо!

Продолжение, это программа, которую я написал в соответствии с Lars (см. Раздел Ответа ниже), но не совсем то, что я хотел:

 int main(int argc, char** argv){

        int pfd[2];
        if (pipe(pfd) == -1) { perror("pipe"); }


        if (fork()==0) { // child reads from pipe
                close(pfd[1]);

                mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
                int ufd = open("user_study.log", O_CREAT | O_APPEND | O_WRONLY, mode);
                if (ufd == -1) {
                        perror("Cannot open output file"); exit(1);
                } //   

                char buf;
                while (read(pfd[0], amp;buf, 1) > 0) {
                        write(STDOUT_FILENO, amp;buf, 1); // write to stdout
                        write(ufd, amp;buf,1);            //   and to log
                }

                close(pfd[0]);

        } else { // parent write to pipe
                // dup STDOUT to the pipe
                close(pfd[0]);
                dup2(pfd[1], STDOUT_FILENO);

                char msg[200];
                msg[0] = "";
                do {
                        scanf("%s", msg);
                        printf("program response..");

                } while (strcmp(msg, "exit")!=0);

                close(pfd[1]);

        }

        return 1;
}
  

Фактический запуск:

 [feih@machine ~/mytest]$ ./a.out
abc
haha
exit 
program response..   <---- the output is delayed by the chld process, not desired
program response..
program response..

[feih@machine ~/mytest]$ less user_study.log
program response..   <---- the log doesn't contain input
program response..
program response..
  

Желаемый запуск и журнал (имитация):

 [feih@machine ~/mytest]$ ./a.out
abc
program response..
haha
program response..
exit 
program response..


[feih@machine ~/mytest]$ less user_study.log 
abc
program response..      <--- the log should be the same as the running
haha
program response..
exit 
program response..
  

Итак, до сих пор эта проблема не была полностью решена.

Комментарии:

1. То есть вы хотите, чтобы каждый printf (и т.д.) записывал данные как в stdout , так и в файл?

2. Результат такой же, как вы сказали. Но вместо того, чтобы делать это на printf стороне, я хочу сделать это на stdout стороне. Вроде как одноразовая настройка, поскольку printf может быть везде.

3. У вас не может быть вспомогательной функции, которую вы используете вместо printf ? И есть ли у этой вспомогательной функции вызов printf и fprintf ?

4. Если вы хотите, чтобы журнал / стандартный вывод содержал входные данные, вам нужно явно повторить их. Вы также захотите установить буферизацию стандартного вывода родительского сервера равной none (см. setbuf).

5. Звучит так, как будто вы хотите реализовать что-то вроде script .

Ответ №1:

Вы можете сделать это:

  • создайте канал (см. pipe(2) )
  • форк
  • в дочернем элементе считывайте из канала и записывайте в каждый вывод
    • стандартный вывод и файл, или что вам нужно
  • в родительском, перенаправьте стандартный вывод в канал (см. dup2(2) )

Есть куча сложностей, о которых вам нужно позаботиться, но это выполнимо.

Вы не можете сделать это без дополнительного процесса, поскольку printf выполняет запись только в один файловый дескриптор (стандартный вывод).

Комментарии:

1. Вы могли бы сделать что-то подобное со вторым потоком вместо разветвления, но вам пришлось бы сначала дублировать стандартный вывод, затем закрыть его и заменить его на конец канала записи.

2. Ларс, я попробовал твое предложение, но это не совсем то, что я хотел: