Ruby,exec,system和%x()或反引号之间的区别

Posted

技术标签:

【中文标题】Ruby,exec,system和%x()或反引号之间的区别【英文标题】:Ruby, Difference between exec, system and %x() or Backticks 【发布时间】:2011-09-14 09:33:59 【问题描述】:

以下 Ruby 方法有什么区别?

execsystem%x()反引号

我知道它们用于通过 Ruby 以编程方式执行终端命令,但我想知道为什么会有三种不同的方法来执行此操作。

【问题讨论】:

这些命令以及许多其他命令在文档中得到了很好的解释:execsystembackticks 关于该主题有一篇很棒的 Ruby 快速提示文章:Execute shell commands。 由于有人刚刚挖掘了这个旧线程,“使用 Unix 进程”对于对该主题感兴趣的 Ruby 爱好者来说是一本极好的书:workingwithunixprocesses.com 我很惊讶没有一个答案提到sh @Dennis 当我提出这个问题时,ruby 1.9.3* 没有发布。 【参考方案1】:

系统

system 方法调用系统程序。您必须将命令作为字符串参数提供给此方法。例如:

>> system("date")
Wed Sep 4 22:03:44 CEST 2013
=> true

被调用的程序将使用 Ruby 程序的当前 STDINSTDOUTSTDERR 对象。实际上,实际返回值要么是true,要么是false,要么是nil。在示例中,日期是通过STDIN 的 IO 对象打印的。如果进程以零状态退出,该方法将返回true,如果进程以非零状态退出,则返回false,如果执行失败,则返回nil

从 Ruby 2.6 开始,传递 exception: true 将引发异常,而不是返回 falsenil

>> system('invalid')
=> nil

>> system('invalid', exception: true)
Traceback (most recent call last):
...
Errno::ENOENT (No such file or directory - invalid)

另一个副作用是全局变量$? 被设置为Process::Status 对象。该对象将包含有关调用本身的信息,包括被调用进程的进程标识符 (PID) 和退出状态。

>> system("date")
Wed Sep 4 22:11:02 CEST 2013
=> true
>> $?
=> #<Process::Status: pid 15470 exit 0>

反引号

Backticks (``) 调用系统程序并返回其输出。与第一种方法相反,命令不是通过字符串提供的,而是通过将其放在反引号对中。

>> `date`
=> Wed Sep 4 22:22:51 CEST 2013   

全局变量$? 也是通过反引号设置的。使用反引号,您还可以使用字符串插值。

%x()

使用%x 是反引号样式的替代方法。它也会返回输出。就像它的亲戚%w%q(以及其他)一样,只要括号样式的分隔符匹配,任何分隔符就足够了。这意味着%x(date)%xdate%x-date- 都是同义词。就像反引号%x 可以利用字符串插值。

执行

通过使用Kernel#exec,当前进程(您的Ruby 脚本)被通过exec 调用的进程替换。该方法可以将字符串作为参数。在这种情况下,字符串将受到外壳扩展。当使用多个参数时,第一个用于执行程序,以下作为参数提供给要调用的程序。

Open3.popen3

有时所需的信息会写入标准输入或标准错误,您也需要控制这些信息。这里Open3.popen3 派上用场了:

require 'open3'

Open3.popen3("curl http://example.com") do |stdin, stdout, stderr, thread|
   pid = thread.pid
   puts stdout.read.chomp
end

【讨论】:

为了更精细地控制呼叫处理STDINSTDOUTSTDERR,请考虑使用Open3.popen3;例如见***.com/a/10922097/258662 感谢您提到反引号支持字符串插值,这解决了我的问题。【参考方案2】:

这是基于this answer 的流程图。另请参阅using script to emulate a terminal。

【讨论】:

这不是那么简单。在我的情况下,“可以(并且需要)阻止直到过程完成”然后使用 popen3 检查 STDOUT/STDERR 输出。 您始终可以通过将其包装在 while 循环中来对(有效)阻塞进行非阻塞调用。你不能这么轻易地将阻塞调用变成非阻塞调用。 典型的 *** - 每个人都很关键,但老实说,这个流程图非常方便,对我帮助很大。谢谢。【参考方案3】:

他们做不同的事情。 exec 用新进程替换当前进程并且永不返回system 调用另一个进程并将其返回其退出值 给当前进程。使用反引号调用另一个进程并将该进程的输出返回到当前进程。

【讨论】:

以上是关于Ruby,exec,system和%x()或反引号之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

perl 系统调用无法识别路径

ruby中执行shell命令找到进程并kill掉

使用 System.Text.Json 使用动态键查询或反序列化 json

如何在 C 或 C++ 中包装参数并将它们传递给 system 或 exec*

ruby 中%Q %q %W %w %x %r %s的用法

Python中Bash反引号的等价物[重复]