如何从Ruby程序内部调用shell命令?然后如何将这些命令的输出返回到Ruby中?


当前回答

如果你真的需要Bash,请参考“最佳”答案中的注释。

首先,请注意,当Ruby调用shell时,它通常调用/bin/sh,而不是Bash。在所有系统上/bin/sh不支持某些Bash语法。

如果你需要使用Bash,在你想要的调用方法中插入Bash -c "your Bash-only command":

quick_output = system("ls -la")
quick_bash = system("bash -c 'ls -la'")

测试:

system("echo $SHELL")
system('bash -c "echo $SHELL"')

或者如果您正在运行一个现有的脚本文件,如

script_output = system("./my_script.sh")

Ruby应该尊重shebang,但你总是可以使用

system("bash ./my_script.sh")

为了确保这一点,尽管/bin/sh运行/bin/bash可能会有轻微的开销,但您可能不会注意到。

其他回答

我绝对不是Ruby专家,但我还是会试一试:

$ irb 
system "echo Hi"
Hi
=> true

你还应该能够做以下事情:

cmd = 'ls'
system(cmd)

如果你真的需要Bash,请参考“最佳”答案中的注释。

首先,请注意,当Ruby调用shell时,它通常调用/bin/sh,而不是Bash。在所有系统上/bin/sh不支持某些Bash语法。

如果你需要使用Bash,在你想要的调用方法中插入Bash -c "your Bash-only command":

quick_output = system("ls -la")
quick_bash = system("bash -c 'ls -la'")

测试:

system("echo $SHELL")
system('bash -c "echo $SHELL"')

或者如果您正在运行一个现有的脚本文件,如

script_output = system("./my_script.sh")

Ruby应该尊重shebang,但你总是可以使用

system("bash ./my_script.sh")

为了确保这一点,尽管/bin/sh运行/bin/bash可能会有轻微的开销,但您可能不会注意到。

如果您有一个比普通情况更复杂的情况,不能用' '来处理,那么请检查Kernel.spawn()。这似乎是Ruby提供的用于执行外部命令的最通用/功能最齐全的程序。

你可以用它来:

创建进程组(Windows)。 重定向进,出,错误文件/彼此。 设置env vars, umask。 执行命令前请更换目录。 设置CPU/数据等资源限制。 在其他答案中做其他选项可以做的所有事情,但需要更多的代码。

Ruby文档中有足够好的例子:

env: hash
  name => val : set the environment variable
  name => nil : unset the environment variable
command...:
  commandline                 : command line string which is passed to the standard shell
  cmdname, arg1, ...          : command name and one or more arguments (no shell)
  [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
options: hash
  clearing environment variables:
    :unsetenv_others => true   : clear environment variables except specified by env
    :unsetenv_others => false  : dont clear (default)
  process group:
    :pgroup => true or 0 : make a new process group
    :pgroup => pgid      : join to specified process group
    :pgroup => nil       : dont change the process group (default)
  create new process group: Windows only
    :new_pgroup => true  : the new process is the root process of a new process group
    :new_pgroup => false : dont create a new process group (default)
  resource limit: resourcename is core, cpu, data, etc.  See Process.setrlimit.
    :rlimit_resourcename => limit
    :rlimit_resourcename => [cur_limit, max_limit]
  current directory:
    :chdir => str
  umask:
    :umask => int
  redirection:
    key:
      FD              : single file descriptor in child process
      [FD, FD, ...]   : multiple file descriptor in child process
    value:
      FD                        : redirect to the file descriptor in parent process
      string                    : redirect to file with open(string, "r" or "w")
      [string]                  : redirect to file with open(string, File::RDONLY)
      [string, open_mode]       : redirect to file with open(string, open_mode, 0644)
      [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
      [:child, FD]              : redirect to the redirected file descriptor
      :close                    : close the file descriptor in child process
    FD is one of follows
      :in     : the file descriptor 0 which is the standard input
      :out    : the file descriptor 1 which is the standard output
      :err    : the file descriptor 2 which is the standard error
      integer : the file descriptor of specified the integer
      io      : the file descriptor specified as io.fileno
  file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
    :close_others => false : inherit fds (default for system and exec)
    :close_others => true  : dont inherit (default for spawn and IO.popen)

在我看来,这是关于在Ruby中运行shell脚本的最好的文章:“在Ruby中运行shell命令的6种方法”。

如果您只需要获得输出,请使用反勾号。

我需要更高级的东西,比如STDOUT和STDERR,所以我使用了Open4 gem。这里已经解释了所有的方法。

下面是我在OS X上的ruby脚本中使用的一个很酷的脚本(这样我就可以在切换离开窗口后启动脚本并获得更新):

cmd = %Q|osascript -e 'display notification "Server was reset" with title "Posted Update"'|
system ( cmd )