跳到内容

命令字面量

命令字面量是用反引号 `%x 百分号字面量分隔的字符串。它将在运行时被子 shell 中执行字符串的捕获输出替换。

与普通字符串一样,相同的 转义插值规则 适用。

与百分号字符串字面量类似,%x 的有效分隔符是圆括号 ()、方括号 []、大括号 {}、尖括号 <> 和管道 ||。除了管道之外,所有分隔符都可以嵌套;这意味着字符串内部的起始分隔符将转义下一个结束分隔符。

特殊变量 $? 持有命令的退出状态,作为 Process::Status。它仅在与命令字面量相同的范围内可用。

`echo foo`  # => "foo"
$?.success? # => true

在内部,编译器将命令字面量重写为对顶层方法 `() 的调用,该方法带有包含命令作为参数的字符串字面量:`echo #{argument}`%x(echo #{argument}) 将被重写为 `("echo #{argument}")

安全问题

虽然命令字面量可能对简单的脚本式工具有用,但在插值用户输入时要格外小心,因为它很容易导致命令注入。

user_input = "hello; rm -rf *"
`echo #{user_input}`

此命令将写入 hello,然后删除当前工作目录中的所有文件和文件夹。

为了避免这种情况,命令字面量通常不应与插值的用户信息一起使用。标准库中的 Process 提供了一种安全的方式将用户信息作为命令参数提供

user_input = "hello; rm -rf *"
process = Process.new("echo", [user_input], output: Process::Redirect::Pipe)
process.output.gets_to_end # => "hello; rm -rf *"
process.wait.success?      # => true