运行shell命令和捕获输出的Crystal语言

4

我习惯于使用open3在Ruby中运行命令。由于在crystal-lang中似乎没有等效的库,所以我制作了以下代码:

    def run_cmd(cmd, args)
      stdout_str = IO::Memory.new
      stderr_str = IO::Memory.new
      result = [] of Int32 | String
      status = Process.run(cmd, args: args, output: stdout_str, error: stderr_str)
      if status.success?
        result = [status.exit_code, "#{stdout_str}"]
      else
        result = [status.exit_code, "#{stderr_str}"]
      end
      stdout_str.close
      stderr_str.close
      result
    end

    cmd = "ping"
    hostname = "my_host"
    args = ["-c 2", "#{hostname}"]
    result = run_cmd(cmd, args)
    puts "ping: #{hostname}: Name or service not known" if result[0] != 0

有更好的方法吗?这是一位退休的网络专家提出的问题,他不是软件开发人员,正在探索crystal-lang。

感谢所有建议。

1个回答

14

可能是这个:

def run_cmd(cmd, args)
  stdout = IO::Memory.new
  stderr = IO::Memory.new
  status = Process.run(cmd, args: args, output: stdout, error: stderr)
  if status.success?
    {status.exit_code, stdout.to_s}
  else
    {status.exit_code, stderr.to_s}
  end
end

我们不需要关闭 IO::Memory,因为它不代表任何操作系统资源的句柄,只是一个内存块,而且我们使用元组来替代数组进行返回。这意味着调用者知道我们要返回确切的两个项目,第一个是数字,第二个是字符串。对于数组的返回,调用者只知道我们返回了任意数量的项,其中任何一项都可能是 int32 或字符串。

你可以像这样使用它:

cmd = "ping"
hostname = "my_host"
args = ["-c 2", hostname]
status, output = run_cmd(cmd, args)
puts "ping: #{hostname}: Name or service not known" unless status == 0

太好了!非常感谢你。 - lewis
我最终也得出了相同的结论,但最初我使用的是stdout.gets_to_end,结果返回了一个空字符串。而to_s则按预期工作。这种行为让我感到惊讶。它是由什么引起的呢? - harm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接