Dash 和 C: eval "$(<cmdfile)" 和 system("eval \"\$(<cmdfile)\"") 给

Posted

技术标签:

【中文标题】Dash 和 C: eval "$(<cmdfile)" 和 system("eval \\"\\$(<cmdfile)\\"") 给出不同的结果【英文标题】:Dash and C: eval "$(<cmdfile)" and system("eval \"\$(<cmdfile)\"") giving different resultsDash 和 C: eval "$(<cmdfile)" 和 system("eval \"\$(<cmdfile)\"") 给出不同的结果 【发布时间】:2020-01-10 09:16:10 【问题描述】:

我想使用 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() 肯定在做某事,因为如果我给它一个不存在的文件名,dash 会抱怨:

$ ./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 的内容?我仅限于在命令行中使用 dash 的内置命令,因此无法使用 ./systest "eval \"\$(cat cmdfile)\"" 等选项。此外,"$(&lt;cmdfile)" 的扩展应该只发生在 system() 内,而不是之前(因此 ./systest "eval \"$(&lt;cmdfile)\"" 将不起作用。

我用破折号 0.5.10.2-6 和破折号 0.5.8-2.1ubuntu2 对此进行了测试。

感谢您的任何见解!

编辑

感谢 Jonathan Leffler 的评论,我现在意识到 dash 不理解 $(&lt;file) 语法。那么什么是兼容破折号的等价物?

总结

所以我的困惑是由于 system(...) 总是使用 /bin/sh,但是在命令行上测试我的表达式时,我不小心调用了 bash 而不是 dash。因此结果不同。

【问题讨论】:

$(&lt;file) 是基于 POSIX shell 的 Bash 扩展。我希望 Dash 会抱怨或误解它。注意system运行sh从错误信息来看。 感谢@JonathanLeffler 的评论。 /bin/sh(和 /usr/bin/sh)是指向我系统上 dash 的符号链接。如果破折号不理解 $( 为什么$前面的反斜杠? $(&lt;file) 的 POSIX 等效项是 $(cat file)。如果你只能使用 Dash 内置命令,你可能会被卡住。谁对你施加了这种限制,为什么?太荒谬了。 @alk,这样括号内的表达式只会在 system() 中扩展,而不是之前。 【参考方案1】:

正确的解决方法是在脚本中添加一个 shebang 行并将其标记为可执行。

#!/bin/sh
echo "hello"

shebang 必须是文件的绝对第一行(它的前两个字节应该是#!)。在这里引用echo 的参数并不是绝对必要的,而是一种良好的做法。 (另见When to wrap quotes around a shell variable?)

当您刚刚创建文件时,只需更改一次权限:

chmod +x ./cmdfile

现在,您可以简单地使用

system("./cmdfile")

【讨论】:

【参考方案2】:

$(&lt; …) 替换与 POSIX-sh 不兼容,但您的 sh 仅限于此。一般的替代方法是将&lt; cmdfile 替换为cat cmdfile

./systest "eval \"\$(cat cmdfile)\""

但我认为dot-sourcing 在这种情况下是等效的:

./systest '. ./cmdfile'

【讨论】:

以上是关于Dash 和 C: eval "$(<cmdfile)" 和 system("eval \"\$(<cmdfile)\"") 给的主要内容,如果未能解决你的问题,请参考以下文章

eval(data)和eval("("+data+")")的区别

是否有任何 Mpeg DASH 的测试链接:type = "dynamic" 和具有多种表示(比特率)?

Ubuntu下shell脚本运行异常:bash和dash的区别

无法使用 Python 3.6.4 版安装“dash”

为啥 DASH 流是基于 HTTP 的“动态”自适应流

ASP.NET 中的 <%# Bind("") %> 和 <%# Eval("") %> 有啥区别?