【发布时间】:2019-07-04 17:00:08
【问题描述】:
我有一个 shell 脚本,它将执行如下所示的内容:
文件:example.sh
#!/bin/sh
#some other code
echo "someconfig">config_file
我希望 config_file 只包含 someconfig ,但是 config_file 发生了奇怪的事情,它在第一行有一个 'c'。我在执行example.sh的父进程中没有找到printf('c')
我的进程会这样调用linux c函数来执行脚本:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/types.h>
int execute_shell(const char *shell)
{
pid_t pid;
int iRet = 0;
if((pid = fork()) < 0)
{
return -1;
}
else if (pid == 0)
{
execlp("sh", "sh", "-c", shell, (char*)0);
exit(127);
}
else
{
while (waitpid(pid, &iRet, 0) < 0) {
if (errno != EINTR) {
iRet = -1;
break;
}
}
}
if(WIFEXITED(iRet) == 0)
{
return -1;
}
if(WEXITSTATUS(iRet) != 0)
{
return -1;
}
return 0;
}
int main()
{
char shell_cmd[1024]="./example.sh";
if( execute_shell(shell_cmd) == -1 )
{
// handle error
}
/*other code blew,may be will write to stdout*/
return 0;
}
有时配置文件看起来很奇怪,而不是 shell 脚本回显的内容。
我用cmd来分析可能性: strace -f ./fork
[pid 12235] open("config_file", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
[pid 12235] fcntl(1, F_GETFD) = 0
[pid 12235] fcntl(1, F_DUPFD, 10) = 10
[pid 12235] fcntl(1, F_GETFD) = 0
[pid 12235] fcntl(10, F_SETFD, FD_CLOEXEC) = 0
[pid 12235] dup2(3, 1) = 1
[pid 12235] close(3) = 0
[pid 12235] fstat(1, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
[pid 12235] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fbabb409000
[pid 12235] write(1, "someconfig\n", 11) = 11
[pid 12235] dup2(10, 1) = 1
[pid 12235] fcntl(10, F_GETFD) = 0x1 (flags FD_CLOEXEC)
[pid 12235] close(10) = 0
[pid 12235] rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
[pid 12235] read(255, "", 52) = 0
[pid 12235] exit_group(0) = ?
[pid 12235] +++ exited with 0 +++
<... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 12235
我不明白function = num是什么意思? 如果有人分析 strace 输出的含义,我将不胜感激。
我怀疑父母和孩子写入标准输出,导致配置中的奇怪输出。
在我的项目中,我们只是使用 linux c 代码执行一个 shell 脚本,它会将 someconfig 回显到 config_file,它正常运行 6 个月,但是有一天配置看起来很奇怪(两台机器,同样的错误,第一行用 c不是它的回声)。
我只是想谈谈是否有可能发生这种情况,以便找到解决问题的方向。
分析strace输出后,子进程执行一些fd操作,确保子进程和父进程回显到不同的fd。所以我认为没有可能使配置混乱。
【问题讨论】:
-
查看
man工具以获取有关strace等工具的更多信息:man strace。它说“跟踪中的每一行都包含系统调用名称,后面是括号中的参数及其返回值。”并举个例子 -
你能用问题中的最少代码重现问题吗?或者只有在
#some other code或/*other code blew,may be will write to stdout*/处添加一些东西? -
如果
execlp成功,它永远不会返回,所以你的else { _exit(0); }是多余的。 -
函数:
waitpid()需要以下语句:#include <sys/types.h>和#include <sys/wait.h>编译时,始终启用警告,然后修复这些警告。 (对于gcc,至少使用:-Wall -Wextra -Wconversion -pedantic -std=gnu11)注意:其他编译器使用不同的选项来产生相同的输出 -
@user3629249 成功则不返回。
if是多余的但不是无效的