命令字面量¶
命令字面量是用反引号 `
或 %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