如何在开始另一个使用它的进程之前完全关闭文件写入?

时间:2018-09-17 21:06:53

标签: c linux

我的程序创建了一个Linux shell文件,然后调用'popen'来执行它。令我不时感到惊讶的是,我收到以下消息:/bin/bash: bad interpreter: Text file busy。因此,我正在寻找一种解决此问题的方法。有什么建议么?

这是我正在做的基本代码:

FILE *f = fopen(shFile, "w");
fprintf(f, ...);
...
fclose(f);

FILE *job = popen(shFile, "r");
...

因此,两个进程都在同一台机器上运行,不涉及“ nfs”,但是popen进程仍认为该文件已打开以进行写入,即使我确实关闭了该文件也是如此。因此,某些系统缓冲区尚未刷新。

看起来sync()有用(尽管很难说)。但是,它会大大减慢一切。

1 个答案:

答案 0 :(得分:0)

当您离开内核以使用shebang确定要与脚本文件一起使用的解释器时,内核必须像对二进制文件一样对脚本文件进行类似的“锁定”。 (这是一个内核内部的“锁”,您只能从用户空间观察。如果该文件已打开以供任何人写入,则该锁将以ETXTBUSY失败。)

避免这种情况很简单。即使使用脚本名作为参数来执行解释器,您也可以自由编辑脚本文件,即使它们正在被解释。

在OP的情况下,这意味着执行bash %s,其中%sshFile的内容代替。这也意味着shFile所引用的文件不需要可执行。仅可读。

如果我们假设shFile不包含任何'字符,那么在Linux中使用它就足够了

char *jobcmd = NULL;
FILE *job;

if (asprintf(&jobcmd, "bash '%s'", shFile) == -1) {
    /* Typically an out of memory error. */
    fprintf(stderr, "%s.\n", strerror(errno));
    exit(EXIT_FAILURE);
}

errno = ENOMEM;
job = popen(jobcmd, "r");
if (!job) {
    fprintf(stderr, "Cannot execute %s: %s.\n", shFile, strerror(errno));
    exit(EXIT_FAILURE);
}

free(jobcmd);
jobcmd = NULL;

通常,您应该考虑一个定制例程,该例程构造以文件名作为参数来执行所需解释器的sh shell命令,并在必要时应用任何转义。 (在POSIX sh shell中,可以使用'"'"'对单引号引起来的单引号进行转义。)


如果脚本仅执行一次,则可以使用popen() / getline()fread()fgetc() / pclose()的自定义替换来编写脚本转换为解释程序的标准输入(此处为bash -s),同时还将脚本的输出检索到单个数组,每行一行(也许使用回调函数?)或逐个字符。这种方法的好处是脚本永远不会存储在任何文件系统上。


通常,将脚本安装为二进制文件的一部分,并通过命令行参数(例如,bash /usr/share/yourapp/somescript.bash 'arg1' 'arg2')为其提供任何详细信息,这是更常见的做法,因此绝对建议这样做。

在Linux和BSD中,这些脚本通常放在/usr/lib/yourapp//usr/share/yourapp/下。