破折号和C:eval“ $(<cmdfile)”和system(“ eval \” \ $(<cmdfile)\“”)给出不同的结果

时间:2019-09-08 07:13:00

标签: c shell command-line eval hyphen

我想在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而不是破折号。因此结果是不同的。

2 个答案:

答案 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")