Чтобы упростить Thomas Dickey's и Chris Ответы Додда, типичный код для выбора того, какой дескриптор используется для ссылки на терминал:
int ttyfd;
/* Check standard error, output, and input, in that order. */
if (isatty(fileno(stderr)))
ttyfd = fileno(stderr);
else
if (isatty(fileno(stdout)))
ttyfd = fileno(stdout);
else
if (isatty(fileno(stdin)))
ttyfd = fileno(stdin);
else
ttyfd = -1; /* No terminal; redirecting to/from files. */
Если ваше приложение настаивает на доступе к управляющему терминалу (терминал, который пользователь использовал для выполнения этого процесса), если он есть, вы можете использовать следующую функцию new_terminal_descriptor()
. Для простоты я встрою его в пример программы:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
int new_terminal_descriptor(void)
{
/* Technically, the size of this buffer should be
* MAX( L_ctermid + 1, sysconf(_SC_TTY_NAME_MAX) )
* but 256 is a safe size in practice. */
char buffer[256], *path;
int fd;
if (isatty(fileno(stderr)))
if (!ttyname_r(fileno(stderr), buffer, sizeof buffer)) {
do {
fd = open(path, O_RDWR | O_NOCTTY);
} while (fd == -1 && errno == EINTR);
if (fd != -1)
return fd;
}
if (isatty(fileno(stdout)))
if (!ttyname_r(fileno(stdout), buffer, sizeof buffer)) {
do {
fd = open(path, O_RDWR | O_NOCTTY);
} while (fd == -1 && errno == EINTR);
if (fd != -1)
return fd;
}
if (isatty(fileno(stdin)))
if (!ttyname_r(fileno(stdin), buffer, sizeof buffer)) {
do {
fd = open(path, O_RDWR | O_NOCTTY);
} while (fd == -1 && errno == EINTR);
if (fd != -1)
return fd;
}
buffer[0] = '\0';
path = ctermid(buffer);
if (path && *path) {
do {
fd = open(path, O_RDWR | O_NOCTTY);
} while (fd == -1 && errno == EINTR);
if (fd != -1)
return fd;
}
/* No terminal. */
errno = ENOTTY;
return -1;
}
static void wrstr(const int fd, const char *const msg)
{
const char *p = msg;
const char *const q = msg + ((msg) ? strlen(msg) : 0);
while (p < q) {
ssize_t n = write(fd, p, (size_t)(q - p));
if (n > (ssize_t)0)
p += n;
else
if (n != (ssize_t)-1)
return;
else
if (errno != EINTR)
return;
}
}
int main(void)
{
int ttyfd;
ttyfd = new_terminal_descriptor();
if (ttyfd == -1)
return EXIT_FAILURE;
/* Let's close the standard streams,
* just to show we're not using them
* for anything anymore. */
fclose(stdin);
fclose(stdout);
fclose(stderr);
/* Print a hello message directly to the terminal. */
wrstr(ttyfd, "\033[1;32mHello!\033[0m\n");
return EXIT_SUCCESS;
}
Функция wrstr()
— это просто вспомогательная функция, которая сразу же записывает указанную строку в указанный файловый дескриптор без буферизации. Строка содержит цветовые коды ANSI, так что в случае успеха она выведет на терминал светло-зеленый Hello!
, даже если стандартные потоки были закрыты.
Если вы сохраните вышеуказанное как example.c
, вы можете скомпилировать его, используя, например.
gcc -Wall -Wextra -O2 example.c -o example
и запустить с помощью
./example
Поскольку new_terminal_descriptor()
использует функцию ctermid()
для получения имени (пути) к управляющему терминалу в качестве крайней меры -- это не является обычным явлением, но я хотел показать здесь, что это легко сделать, если вы решите, что это необходимо -- это будет вывести приветственное сообщение на терминал, даже если все потоки перенаправлены:
./example </dev/null >/dev/null 2>/dev/null
Наконец, если вам интересно, ничто из этого не является «особенным». Я не говорю о консольном терминале, который представляет собой текстовый консольный интерфейс, который многие дистрибутивы Linux предоставляют в качестве альтернативы графической среде, и единственный локальный интерфейс, предоставляемый большинством серверов Linux. Все вышеперечисленное использует только обычные псевдотерминальные интерфейсы POSIX и будет отлично работать, например. xterm
или любого другого обычного эмулятора терминала (или консоли Linux) во всех системах POSIXy — Linux, Mac OS X и вариантах BSD.
person
Nominal Animal
schedule
10.03.2016
fd
, а именноstdin
иstdout
являются файловыми дескрипторами, поэтому это неясно, и мне нужно спросить - person humanityANDpeace   schedule 08.03.2016