我想在C语言中使用 system()函数来评估文件 cmdfile 中的表达式,但结果却不尽相同因此直接在命令行上。 cmdfile 的内容如下:
$ cat cmdfile
echo hello
当我直接在命令行上评估其内容时,它会起作用:
$ eval "$(<cmdfile)"
hello
要在C中执行相同操作,我正在使用system()。这是我的代码:
$ cat systest.c
#include <stdio.h>
#include <string.h>
int main (int argc, char* argv[])
{
char* cmd = argv[1];
printf("%s\n", cmd);
system(cmd);
return 0;
}
麻烦的是,使用上述代码时我看不到任何输出
$ ./systest "eval \"\$(<cmdfile)\""
eval "$(<cmdfile)"
在printf输出之后应立即打印 hello ,但它不起作用。不过,我知道system()肯定在做某件事,因为如果我给它一个不存在的文件名,破折号会抱怨:
$ ./systest "eval \"\$(<cmdfileFF)\""
eval "$(<cmdfileFF)"
sh: 1: cannot open cmdfileFF: No such file
并且,如果我只评估 echo hello 而没有涉及 cmdfile ,它也可以工作:
$ ./systest "eval \"echo hello\""
eval "echo hello"
hello
我想知道是什么导致这种行为差异。还有其他方法来执行破折号 cmdfile 的内容吗?我仅限于在命令行上使用破折号的内置命令,因此无法使用诸如./systest "eval \"\$(cat cmdfile)\""
之类的选项。此外,"$(<cmdfile)"
的扩展仅应在system()内进行,而不是在此之前(因此./systest "eval \"$(<cmdfile)\""
将不起作用。
我用破折号0.5.10.2-6和破折号0.5.8-2.1ubuntu2进行了测试。
谢谢您的见解!
由于乔纳森·莱弗勒(Jonathan Leffler)的评论,我现在意识到破折号不理解$(<file)
语法。那么什么是破折号兼容等效物?
所以我的困惑是由于system(...)始终使用/ bin / sh,但是在命令行上测试表达式时,我不小心调用了bash而不是破折号。因此结果是不同的。
答案 0 :(得分:3)
$(< …)
替换与POSIX-sh不兼容,但是您的sh仅限于此。一般的替代方法是将< cmdfile
替换为cat cmdfile
:
./systest "eval \"\$(cat cmdfile)\""
但是我认为dot-sourcing在这种情况下是等效的:
./systest '. ./cmdfile'
答案 1 :(得分:1)
正确的解决方法是在脚本中放置一个shebang行并将其标记为可执行文件。
#!/bin/sh
echo "hello"
shebang必须绝对是文件的第一行(其前两个字节应为#
和!
)。在这里,echo
引号的引用不是严格必需的,而是良好的实践。 (另请参见When to wrap quotes around a shell variable?)
创建文件后,只需更改一次权限即可:
chmod +x ./cmdfile
现在,您只需使用
system("./cmdfile")