为了简化Thomas Dickey's和Chris Dodd's答案,典型的码要选择哪个描述符被用来指终端是
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()
函数来获取名称(路径)来控制终端作为最后的手段来看 - 这是不常见的,但我想表现在这里很容易,如果你决定有必要做的事 - ,将打印hello消息到终端,甚至在所有数据流都被重定向:
./example </dev/null >/dev/null 2>/dev/null
最后,如果你想知道,没有一个是“特殊”的。我不是在谈论控制台终端,这是许多Linux发行版提供的基于文本的控制台界面,作为图形环境的替代选择,也是大多数Linux服务器提供的唯一本地界面。以上所有使用的只是普通的POSIX伪终端接口,并且可以很好地工作。 xterm
或任何其他普通终端仿真器(或Linux控制台),在所有POSIXy系统 - Linux,Mac OS X和BSD变体中。
fd表示文件描述符 – HoKy22
@ HoKy22谢谢,'fd'的两个选项,即'stdin'和'stdout'都是文件描述符,因此它不是很清楚,我需要询问 – humanityANDpeace