создание нового терминала и запись в его стандартный вывод

#c #terminal

#c #терминал

Вопрос:

У меня есть приложение, которое использует графический интерфейс для выполнения большей части своего взаимодействия с пользователем. Однако я хотел бы иметь отдельное окно терминала, в которое я мог бы записывать некоторые проверки ошибок, необработанные значения и т.д.

Я знаю, что могу создать новый терминал с помощью system() команды, но я понятия не имею, возможно ли взаимодействие.

в наилучшем возможном сценарии я хотел бы иметь функцию, которая принимает строку (массив символов, который я знаю …) и печатает ее во вновь созданном окне консоли:

что-то вроде:

 int func(char *msg) {
    static // initiate some static interface with a newly spawned terminal window.

    // check if interface is still valid

    // send data to terminal

    return 0; //succes

}
  

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

1. взгляните на ncurses

2. Я знаю ncurses, но, насколько я знаю, ncurses не позволяет мне создавать НОВОЕ окно терминала, только управлять текущим открытым окном. Я использовал ncurses в нескольких предыдущих приложениях.

Ответ №1:

  1. Откройте канал.
  2. Форк.
  3. В дочернем процессе закройте конец записи и exec перейдите к xterm запущенному cat /dev/fd/<rdfd> .
  4. В родительском процессе закройте конец чтения и выполните запись в конец записи.
 #include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>

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

    int fds[2];
    if(pipe(fds) == -1) {
        abort();
    }

    int child_pid = fork();
    if(child_pid == -1) {
        abort();
    }

    if(child_pid == 0) {
        close(fds[1]);
        char f[PATH_MAX   1];
        sprintf(f, "/dev/fd/%d", fds[0]);
        execlp("xterm", "xterm", "-e", "cat", f, NULL);
        abort();
    }

    close(fds[0]);
    write(fds[1], "Hi there!n", sizeof("Hi there!n"));
    sleep(10);
    close(fds[1]);
    sleep(3);

    return EXIT_SUCCESS;
}
  

Вы можете использовать fdopen для превращения fds[1] в FILE * который вы можете использовать fprintf и тому подобное.

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

1. Мне нравится этот подход, разветвление и использование pid, вероятно, намного проще, чем открывать другой процесс отдельно и отправлять команды через сокет.

2. Спасибо. Это работает! хотя мне вроде как не нравится fork()

Ответ №2:

Хорошо, представьте сценарий, в котором терминал является вашим основным устройством вывода (например, tty [n]), как бы тогда открыть «новый» терминал?

Единственная причина, по которой вы можете открывать несколько терминалов в графическом DE, заключается в том, что они являются эмуляторами терминала. Вам нужно будет запустить другой эмулятор терминала и записать в стандартный вывод этого, используя что-то вроде сокета или, возможно, разделяемой памяти.

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

1. tl; dr: нет стандартного способа

2. это отстой… /dev/pts содержит все виртуальные терминалы, но есть ли способ, которым я могу идентифицировать или «назвать» вновь созданный терминал? pts позволило бы мне создать новый терминал, но привязка его к эмулятору терминала не документирована

3. Просто откройте сокет и отправьте свои команды и что-то еще через него на другой терминал, тогда все, что вам нужно, это тот же номер порта. Если вы не хотите этого делать, вы могли бы использовать общий файл или общую память (подход shm был бы быстрее), но это огромный риск для безопасности; если это имеет значение с вашей точки зрения

4. posix_openpt(), за которым следует unlockpt() затем получаем имя (/dev/pts/x) с помощью ptsname()