我的程序创建了一个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()
有用(尽管很难说)。但是,它会大大减慢一切。
答案 0 :(得分:0)
当您离开内核以使用shebang确定要与脚本文件一起使用的解释器时,内核必须像对二进制文件一样对脚本文件进行类似的“锁定”。 (这是一个内核内部的“锁”,您只能从用户空间观察。如果该文件已打开以供任何人写入,则该锁将以ETXTBUSY
失败。)
避免这种情况很简单。即使使用脚本名作为参数来执行解释器,您也可以自由编辑脚本文件,即使它们正在被解释。
在OP的情况下,这意味着执行bash %s
,其中%s
被shFile
的内容代替。这也意味着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/
下。