为什么 snprintf 在 %s 之后不读取?

Why is snprintf not reading after %s?

我正在尝试编写一个程序来检查 /home/user 目录 下是否存在某个位置。为此,我必须使用 whoami 命令获取用户名并将其输出添加到缓冲区以使用 locate 命令。

然而,即使 snprintf 读取了 whoami 命令,它也没有读取其余部分。我进行了几次搜索,得出的结果是 NULL 可能不会在字符串末尾终止。然而,我找不到如何手动终止它。我不确定是什么问题,所以,我在这里。

下面是更好地演示我的问题的代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include <string.h>
    
char *readFile(char *);
bool check();
    
bool check() {
    char path[200] = { 0 };
    
    snprintf(path, 200, "/home/%s/.example", readFile("whoami"));
    
    char lll[300] = { 0 };
    
    snprintf(lll, 300, "locate %s", path);
    
    char *buffer = readFile(lll);
    
    if (strcmp(buffer, path) == 0) {
        return true;
    } else {
        return false;
    }
}

char *readFile(char cmd[200]) {
    char cmd1[99999] = { 0 };
    system("touch cmd");  
    snprintf(cmd1, 99999, "%s >> cmd", cmd);
    system(cmd1); 
        
    FILE *f = fopen("cmd", "rt");
    assert(f);
    fseek(f, 0, SEEK_END);
    long length = ftell(f);
    fseek(f, 0, SEEK_SET);
    char *buffer = (char *)malloc(length + 1);
    buffer[length] = '[=10=]';
    fread(buffer, 1, length, f);
    fclose(f);
    system("rm cmd");
    return buffer;
}
    
int main() {
    int x = check();
    
    if (x == 1)
        printf("There is a location like that");
    else
        printf("There isn't");
    
    return 0;
}

whoami 命令打印出当前用户的名称,以换行符结束。将文件 cmd 读回 buffer 将包含相同的换行符。

path 字符串将是 "/home/USERNAME\n/.example"。试图执行 locate /home/USERNAME\n/.example 可能会混淆 system 函数。

解决方案应该是去除 readFile 中的最后一个换行符。

您的 readFile 函数存在一些问题:

  • 该名称具有误导性,应为 runCommand 或类似名称。

  • 您将命令输出附加到 cmd 文件。如果 cmd 文件在您 运行 您的程序之前存在,这将导致意外结果。你应该改为写:

    snprintf(cmd1, 99999, "%s > cmd", cmd);
    
  • 命令输出可能有尾随换行符。你应该 trim 输出。

这是修改后的版本:

#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *readFile(const char *cmd) {
    /* construct the command */
    size_t size = 4 + strlen(cmd) + 1;
    char *cmd1 = malloc(size);
    assert(cmd1);
    snprintf(cmd1, size, "%s > cmd", cmd);

    /* run the command */
    system(cmd1);
    free(cmd1);
        
    /* read the output file */
    FILE *f = fopen("cmd", "rt");
    assert(f);
    fseek(f, 0, SEEK_END);
    long length = ftell(f);
    fseek(f, 0, SEEK_SET);
    char *buffer = malloc(length + 1);
    buffer[length] = '[=11=]';
    fread(buffer, 1, length, f);
    fclose(f);
    unlink("cmd");

    /* trim trailing white space from the output */
    while (length > 0 && isspace((unsigned char)buffer[length - 1])) {
        buffer[--length] = '[=11=]';
    }
    /* trim leading white space from the output */
    size_t i = 0;
    while (isspace((unsigned char)buffer[i]) {
        i++;
    }
    if (i > 0) {
        memmove(buffer, buffer + i, length - i + 1);
    }
    return buffer;
}

因为 Linux 有一个你的主目录的快捷方式(“~”),整个“whoami”/“getuid”混乱可以通过使用来避免:

char *buffer = readFile("locate ~/.example");

您仍然可能需要 trim 关闭尾随换行符 and/or CR 字符,也许是:

strtok(buffer,"\r\n\t ");

或者更好,正如@chqrlie 在下面建议的那样。