使用 NCurses 和 C 显示系统信息的简单文本 GUI (TUI)
Simple Text GUI (TUI) Using NCurses and C to Display System Info
我刚刚开始尝试结合 ncurses 和 C 来开发一个非常小的 TUI。 TUI 的目的是用基本的 login/welcome 屏幕迎接用户。目标是显示基本的系统信息,如操作系统、可用内存、IP 地址等。除了只读之外什么都没有。
执行此操作的最佳方法是什么?我正在努力处理的部分是将 shell 命令(如 df
、ls
、ifconfig
等)与我可以在 ncurses 和 C 中显示或打印的变量连接起来。我知道可以这样做,也可以用字符串调用系统命令,但这看起来有点笨重:
#include <ncurses.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
FILE *pp;
initscr();
cbreak();
if ((pp = popen("df", "r")) != 0) {
char buffer[BUFSIZ];
while (fgets(buffer, sizeof(buffer), pp) != 0) {
addstr(buffer);
}
pclose(pp);
}
getch();
return EXIT_SUCCESS;
}
是否有任何方法可以从 C 程序中的命令行中执行命令,然后有选择地访问该命令的输出以供以后显示?或者这些信息通常存储在机器上可解析文件的某个地方?我刚开始尝试以 "TUI" 的方式将 system information/use 拉入命令行,如有任何帮助,我们将不胜感激。提前致谢!
管道的想法既好又简单,其他任何东西都至少缺少 "good and simple" 之一,很可能两者都缺少。但是您的另一个问题是关于某些系统信息的可用性。好吧,这些信息非常分散,具体位置取决于实际使用的操作系统。
对于普通的非专用Linux系统:文件系统是/etc/mtab
(详细信息使用statfs()
),许多系统信息在[=22] =].如果您需要更多,它会变得复杂。
即使你想构建一个df
的简化版本($COREUTILS/src/df.c
中的df
的原始代码),也已经相当复杂了。而不是仅仅 运行ning df
并从管道读取,你必须做
- 阅读
/etc/mtab
并找到挂载点(系统可能没有/etc/mtab
,尽管它应该有)
- 运行
statfs()
在每个挂载点上打印结果
你需要超过 100 行容易出错的 C 代码,即使你跳过所有花哨的东西。并且仅用于打印文件系统。
不,只需从管道读取经过良好测试的旧程序的输出,这是最简单的方法。
编辑:
如果使用管道,则使用完整 shell。这意味着您也可以使用所有其他工具。
为了让测试更简单,这里有一个没有 ncurses 的简化版本(让它变得更复杂 ;-) ),只是为了在命令行下玩。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 256
// ALL CHECKS OMMITTED!
char *sub_exec(const char *command)
{
char buf[BUF_SIZE];
char *ret;
size_t mem_alloc, mem_needed;
ret = malloc(4 * BUF_SIZE * sizeof(char));
// or use calloc or set [=10=] manually
memset(ret, '[=10=]', 4 * BUF_SIZE);
// memory allocated
mem_alloc = 4 * BUF_SIZE;
// memory needed
mem_needed = 0;
// open the pipe read-only
FILE *out_pipe = popen(command, "r");
// until end of the output of the pipe (EOF)
while (!feof(out_pipe)) {
// read a chunk of the output
if (fgets(buf, BUF_SIZE, out_pipe) != NULL) {
mem_needed += BUF_SIZE;
if (mem_alloc < mem_needed) {
// no fancy algorithms
ret = realloc(ret, mem_needed + 4 * BUF_SIZE);
mem_alloc = mem_needed * 2;
}
// and conatenate it to the result
strncat(ret, buf, BUF_SIZE);
}
}
pclose(out_pipe);
// You may or may not readjust the memory used
// ret = realloc(ret, strlen(ret) + 1);
return ret;
}
int main(int argc, char **argv)
{
char *str_from_pipe;
if (argc < 2)
fprintf(stderr, "Usage: %s command\n", argv[0]);
str_from_pipe = sub_exec(argv[1]);
printf("%s\n", str_from_pipe);
free(str_from_pipe);
exit(EXIT_SUCCESS);
}
你可以在这里做一些简单的事情,比如
./readpipe "cat win*c | tr -d '5' | perl -0777 -pe 's{/\*.*?\*/}{}gs' | indent -"
(连接所有 C 文件,去除 \r
s,去除大部分注释并 运行 通过 indent(1)
)
或 df
。假设您想要其中包含实际数据的文件系统,而不是 tempfs
或类似的文件系统,所以:
./readpipe "df -P -h -t ext4"
此处打印:
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 48G 33G 14G 71% /
/dev/sda3 861G 761G 56G 94% /home
(好像很饱)
您可以直接使用或进一步按摩:
./readpipe "df -h -t ext4 --output=target,fstype,size,used,avail|awk '{if(NR>1)print}'"
打印:
/ ext4 48G 33G 14G
/home ext4 861G 761G 56G
警告:
./readpipe "df -h -t ext4 --output=target,fstype,size,used,avail| sed -n '1!p'"
不行,你需要交换那种报价(但并不总是那么简单)
./readpipe 'df -h -t ext4 --output=target,fstype,size,used,avail | sed -n "1!p"'
为了能够拆分条目,例如:strtok(3)
用单个制表符替换所有空格
./readpipe 'df -h -t ext4 --output=target,fstype,size,used,avail | sed -n "1!p" | sed -e "s/[ ]\+/\t/g"'
(是的,还有更优雅的方法,但已经足够了)
files/directories 中关于 CPU(s)
的更多有用信息
/sys/devices/system/cpu/cpu*/cpufreq/
/sys/devices/system/cpu/cpu*/cache/
或lscpu
。有许多有用的 ls*
程序,例如 lspci
、lsusb
、lskat
…不,等等,那是不同的东西,不要忘记 lsblk
(列出块设备,包括分区(如果可用)。在 lshw
的帮助下可以获得已安装硬件的完整列表(一些信息需要 root 权限,但它已经相当广泛)并且 uname
是关于 OS 的信息,还有:free
内存消耗,还有很多很多。大多数(如果不是全部)允许某种格式,请参阅相应的联机帮助页以了解详细信息。
如果你告诉我你需要什么,我可以告诉你在哪里可以找到它(他大胆地说;-))。只要在下面评论问,我会添加它。
我刚刚开始尝试结合 ncurses 和 C 来开发一个非常小的 TUI。 TUI 的目的是用基本的 login/welcome 屏幕迎接用户。目标是显示基本的系统信息,如操作系统、可用内存、IP 地址等。除了只读之外什么都没有。
执行此操作的最佳方法是什么?我正在努力处理的部分是将 shell 命令(如 df
、ls
、ifconfig
等)与我可以在 ncurses 和 C 中显示或打印的变量连接起来。我知道可以这样做,也可以用字符串调用系统命令,但这看起来有点笨重:
#include <ncurses.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
FILE *pp;
initscr();
cbreak();
if ((pp = popen("df", "r")) != 0) {
char buffer[BUFSIZ];
while (fgets(buffer, sizeof(buffer), pp) != 0) {
addstr(buffer);
}
pclose(pp);
}
getch();
return EXIT_SUCCESS;
}
是否有任何方法可以从 C 程序中的命令行中执行命令,然后有选择地访问该命令的输出以供以后显示?或者这些信息通常存储在机器上可解析文件的某个地方?我刚开始尝试以 "TUI" 的方式将 system information/use 拉入命令行,如有任何帮助,我们将不胜感激。提前致谢!
管道的想法既好又简单,其他任何东西都至少缺少 "good and simple" 之一,很可能两者都缺少。但是您的另一个问题是关于某些系统信息的可用性。好吧,这些信息非常分散,具体位置取决于实际使用的操作系统。
对于普通的非专用Linux系统:文件系统是/etc/mtab
(详细信息使用statfs()
),许多系统信息在[=22] =].如果您需要更多,它会变得复杂。
即使你想构建一个df
的简化版本($COREUTILS/src/df.c
中的df
的原始代码),也已经相当复杂了。而不是仅仅 运行ning df
并从管道读取,你必须做
- 阅读
/etc/mtab
并找到挂载点(系统可能没有/etc/mtab
,尽管它应该有) - 运行
statfs()
在每个挂载点上打印结果
你需要超过 100 行容易出错的 C 代码,即使你跳过所有花哨的东西。并且仅用于打印文件系统。
不,只需从管道读取经过良好测试的旧程序的输出,这是最简单的方法。
编辑:
如果使用管道,则使用完整 shell。这意味着您也可以使用所有其他工具。
为了让测试更简单,这里有一个没有 ncurses 的简化版本(让它变得更复杂 ;-) ),只是为了在命令行下玩。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 256
// ALL CHECKS OMMITTED!
char *sub_exec(const char *command)
{
char buf[BUF_SIZE];
char *ret;
size_t mem_alloc, mem_needed;
ret = malloc(4 * BUF_SIZE * sizeof(char));
// or use calloc or set [=10=] manually
memset(ret, '[=10=]', 4 * BUF_SIZE);
// memory allocated
mem_alloc = 4 * BUF_SIZE;
// memory needed
mem_needed = 0;
// open the pipe read-only
FILE *out_pipe = popen(command, "r");
// until end of the output of the pipe (EOF)
while (!feof(out_pipe)) {
// read a chunk of the output
if (fgets(buf, BUF_SIZE, out_pipe) != NULL) {
mem_needed += BUF_SIZE;
if (mem_alloc < mem_needed) {
// no fancy algorithms
ret = realloc(ret, mem_needed + 4 * BUF_SIZE);
mem_alloc = mem_needed * 2;
}
// and conatenate it to the result
strncat(ret, buf, BUF_SIZE);
}
}
pclose(out_pipe);
// You may or may not readjust the memory used
// ret = realloc(ret, strlen(ret) + 1);
return ret;
}
int main(int argc, char **argv)
{
char *str_from_pipe;
if (argc < 2)
fprintf(stderr, "Usage: %s command\n", argv[0]);
str_from_pipe = sub_exec(argv[1]);
printf("%s\n", str_from_pipe);
free(str_from_pipe);
exit(EXIT_SUCCESS);
}
你可以在这里做一些简单的事情,比如
./readpipe "cat win*c | tr -d '5' | perl -0777 -pe 's{/\*.*?\*/}{}gs' | indent -"
(连接所有 C 文件,去除 \r
s,去除大部分注释并 运行 通过 indent(1)
)
或 df
。假设您想要其中包含实际数据的文件系统,而不是 tempfs
或类似的文件系统,所以:
./readpipe "df -P -h -t ext4"
此处打印:
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 48G 33G 14G 71% /
/dev/sda3 861G 761G 56G 94% /home
(好像很饱)
您可以直接使用或进一步按摩:
./readpipe "df -h -t ext4 --output=target,fstype,size,used,avail|awk '{if(NR>1)print}'"
打印:
/ ext4 48G 33G 14G
/home ext4 861G 761G 56G
警告:
./readpipe "df -h -t ext4 --output=target,fstype,size,used,avail| sed -n '1!p'"
不行,你需要交换那种报价(但并不总是那么简单)
./readpipe 'df -h -t ext4 --output=target,fstype,size,used,avail | sed -n "1!p"'
为了能够拆分条目,例如:strtok(3)
用单个制表符替换所有空格
./readpipe 'df -h -t ext4 --output=target,fstype,size,used,avail | sed -n "1!p" | sed -e "s/[ ]\+/\t/g"'
(是的,还有更优雅的方法,但已经足够了)
files/directories 中关于 CPU(s)
的更多有用信息/sys/devices/system/cpu/cpu*/cpufreq/
/sys/devices/system/cpu/cpu*/cache/
或lscpu
。有许多有用的 ls*
程序,例如 lspci
、lsusb
、lskat
…不,等等,那是不同的东西,不要忘记 lsblk
(列出块设备,包括分区(如果可用)。在 lshw
的帮助下可以获得已安装硬件的完整列表(一些信息需要 root 权限,但它已经相当广泛)并且 uname
是关于 OS 的信息,还有:free
内存消耗,还有很多很多。大多数(如果不是全部)允许某种格式,请参阅相应的联机帮助页以了解详细信息。
如果你告诉我你需要什么,我可以告诉你在哪里可以找到它(他大胆地说;-))。只要在下面评论问,我会添加它。