我想使用sscanf解析/ etc / passwd文件。目前正在尝试下面的代码段
sscanf(buf,"%s:%*s:%*u:%*u:%*s:%*s",
szName, &ncUser_gid);
错了。我只需要解析该用户的用户名和相应的组ID
答案 0 :(得分:3)
基本答案是使用(否定)'扫描集' - 阅读sscanf()
的手册。
if (sscanf(buf, "%[^:]:%*[^:]:%*[^:]:%u", szName, &ncUser_gid) != 2)
将非冒号序列读入szName
,然后跳过冒号,密码字段,冒号,UID字段,冒号,并将下一个字段中的数字读入{{1 }}。它还会检查您是否同时获得了两个值,而忽略了其他尾随字段(comment,home,shell)。
请注意,因为您使用的是ncUser_gid
,所以根本不需要处理任何尾随字段。此外,密码文件条目中有7个字段,而不是6个字段。使用sscanf()
,这不是问题。如果您正在阅读文件,那就是。此外,如果您正在读取文件,则必须担心扫描集不会跳过前导空格,这将是前一行输入中遗留的换行符。对于文件流解析,您需要使用:
sscanf()
请注意,shell字段不必有任何数据。这也会导致空的注释字段,但通常会填充。请注意,它跳过了密码;它在Unix的现代版本中很少有用。
int rc;
if ((rc = fscanf(fp, " %[^:]:%*[^:]:%u:%u:%[^:]:%[^:]:%[^:]",
username, &uid, &gid, comment, homedir, shell)) != 5 && rc != 6)
…handle format error…
if (rc == 5)
shell[0] = '\0';
示例sscanf()
输出:
#include <stdio.h>
int main(void)
{
char buf[] = "root:*:0:1:System Administrator:/var/root:/bin/sh";
char szName[10] = "Pygmalion"; // Make sure it isn't empty!;
unsigned int ncUser_gid = 23456; // Make sure it isn't zero!
if (sscanf(buf, "%[^:]:%*[^:]:%*[^:]:%u", szName, &ncUser_gid) != 2)
printf("Ooops!\n");
else
printf("User: [%s]; GID = %u\n", szName, ncUser_gid);
return 0;
}
(我攻击了该条目,因此UID和GID不同。)
User: [root]; GID = 1
示例fscanf()
请注意,在Mac上,密码文件以多行#include <stdio.h>
int main(void)
{
const char passwd[] = "/etc/passwd";
FILE *fp = fopen(passwd, "r");
if (fp == 0)
{
fprintf(stderr, "failed to open '%s' for reading\n", passwd);
return 1;
}
char username[64];
unsigned uid;
unsigned gid;
char comment[64];
char homedir[64];
char shell[64];
int rc;
while (!feof(fp))
{
if ((rc = fscanf(fp, " %63[^:\n]:%*[^:\n]:%u:%u:%63[^:\n]:%63[^:\n]:%63[^:\n]",
username, &uid, &gid, comment, homedir, shell)) != 5 && rc != 6)
{
int c;
while ((c = getc(fp)) != EOF && c != '\n')
;
}
else
{
if (rc == 5)
shell[0] = '\0';
printf("[%s] %u %u [%s] [%s] [%s]\n", username, uid, gid, comment, homedir, shell);
}
}
return 0;
}
条评论开头。需要#
表示法或类似的表示法来避免解析文件的该部分时出现问题。在没有文件中的这些注释行的理智系统上,没有它们,你可能会离开。另请注意,代码可以保护自己免受字符串字段中的溢出。
此外,我继续使用%[^:\n]
整数表示UID和GID,但unsigned
对UID和GID都有负值nobody
,因此签名类型可能更好。
示例输出:
-2
所有用户都在我的Mac上指定了特定的shell,因此'rc == 5'代码尚未经过测试。
示例输出:
[nobody] 4294967294 4294967294 [Unprivileged User] [/var/empty] [/usr/bin/false]
[root] 0 0 [System Administrator] [/var/root] [/bin/sh]
[daemon] 1 1 [System Services] [/var/root] [/usr/bin/false]
…
JFTR:使用GCC 7.1.0在运行macOS 10.12.5的Mac上测试。 编译命令行如:
[# Open Directory.
##
nobody] 4294967294 4294967294 [Unprivileged User] [/var/empty] [/usr/bin/false