我正在尝试使用创建很多文件C
。我已经做好了mkdir -p directory && touch directory/filename
。当我的循环到达名称中包含特殊字符的文件时,我收到错误
syntax error :" unexpected "("
你能帮助我吗?
答案1
您的问题似乎是,您正在尝试使用类似system()
.强烈建议不要使用system()
,因为它会生成一个 shell 来执行给定的命令。这也意味着,生成的 shell 将使用自己的语法评估完整命令,因此您必须转义 shell 专门处理的字符。
从 C 创建文件和目录的更健壮(且不易出错)的方法是使用为此任务提供的真正的 C 函数,即mkdir()
and open()
/ creat()
:
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int
main(void)
{
char dir[] = "some(directory)with*special[characters]";
char file[] = "some(file)with*the[same]characters";
int fd;
if (mkdir(dir, 0755) == -1)
err(EXIT_FAILURE, "creating directory failed");
if ((fd = open(file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
err(EXIT_FAILURE, "creating file failed");
close(fd);
/* ... */
return 0;
}
答案2
用引号将文件路径括起来,如下所示:
touch "directory/file"
答案3
您需要“引用”文件名:
touch "directory/file with whitespace (and special characters)"
请阅读 bash 手册中有关引用和特殊字符的内容。
答案4
如果您使用system()
insideC
调用带有参数的 shell 命令,最好是使用环境来传递这些参数以避免引用它们。
文件的路径(包含任何字符)存储在file_path
:
if (setenv("FILE", file_path, 1) < 0) {
perror("setenv");
exit(1);
}
system("mkdir -p -- \"$(dirname -- \"$FILE\")\" && touch -- \"$FILE\"");
这样,您就可以将固定字符串传递给sh -c
(由内部调用),并且只要您的 shell 代码正确(请注意上面的引号),system()
就不必担心任意代码注入漏洞。--
(上面有常见的sh
命令替换问题,即所有尾随换行符都被删除,因此它会在file_path
类似的情况下失败foo/bar\n/file
。我将让您决定是否要努力解决这个问题)。
如果您想将 shell 代码中的文件名传递给system()
,请执行以下操作不是做:
sprintf(cmd, "mkdir -p -- \"%s\" && touch -- \"%s\"", dir_path, file_path);
因为这仍然是一个命令注入漏洞(例如,文件名类似于$(reboot)
或";reboot;:"
。如果您使用单引号而不是双引号,则相同。
你需要:
sprintf(cmd, "mkdir -p -- %s && touch -- %s",
shquote(dir_path), shquote(file_path));
whereshquote()
是一个函数(其实现留作练习),它将每个'
字符替换为'\''
单引号并将结果括起来。因此,例如返回'foo'\''bar'
for foo'bar
(请记住,引用文件的长度最多可达 4 * length + 2,在为缓冲区分配空间时需要考虑到这一点cmd
)。
这是最安全的引用方法。使用双引号或反斜杠的引用方法在某些使用外来字符集的区域设置中都存在问题,可能导致任意代码注入漏洞。