作为奖励,在shell命令成功退出(0)并将任何内容放在STDOUT上的情况下,这个也将返回STDOUT . 以这种方式,它与 system 不同,后者在这种情况下只返回 true .
代码如下 . 具体功能是 system_quietly :
require 'open3'
class ShellError < StandardError; end
#actual function:
def system_quietly(*cmd)
exit_status=nil
err=nil
out=nil
Open3.popen3(*cmd) do |stdin, stdout, stderr, wait_thread|
err = stderr.gets(nil)
out = stdout.gets(nil)
[stdin, stdout, stderr].each{|stream| stream.send('close')}
exit_status = wait_thread.value
end
if exit_status.to_i > 0
err = err.chomp if err
raise ShellError, err
elsif out
return out.chomp
else
return true
end
end
#calling it:
begin
puts system_quietly('which', 'ruby')
rescue ShellError
abort "Looks like you don't have the `ruby` command. Odd."
end
#output: => "/Users/me/.rvm/rubies/ruby-1.9.2-p136/bin/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)
20 回答
此解释基于我的一位朋友的评论Ruby script . 如果您想改进脚本,请随时在链接上更新它 .
首先,请注意当Ruby调用shell时,它通常调用
/bin/sh
,而不是Bash . 所有系统上的/bin/sh
都不支持某些Bash语法 .以下是执行shell脚本的方法:
,通常称为反引号 -
cmd``这和许多其他语言一样,包括Bash,PHP和Perl .
返回shell命令的结果 .
文件:http://ruby-doc.org/core/Kernel.html#method-i-60
%x( cmd )
x
字符后面是分隔符,可以是任何字符 . 如果分隔符是字符(
,[
,{
或<
之一,则文字由截至匹配的结束分隔符的字符组成,并考虑嵌套的分隔符对 . 对于所有其他分隔符,文字包括直到下一个分隔符字符出现的字符 . 允许字符串插值#{ ... }
.返回shell命令的结果,就像反引号一样 .
文件:http://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html
Kernel#system
在子shell中执行给定的命令 .
如果找到并成功运行命令,则返回
true
,否则返回false
.文件:http://ruby-doc.org/core/Kernel.html#method-i-system
Kernel#exec
通过运行给定的外部命令替换当前进程 .
返回none,当前进程被替换并且永远不会继续 .
文件:http://ruby-doc.org/core/Kernel.html#method-i-exec
这里有一些额外的建议:
$?
,与$CHILD_STATUS
相同,如果你使用反引号,system()
或%x{}
,则访问最后一个系统执行命令的状态 . 然后,您可以访问exitstatus
和pid
属性:如需更多阅读,请参阅
http://www.elctech.com/blog/i-m-in-ur-commandline-executin-ma-commands
http://blog.jayfields.com/2006/06/ruby-kernel-system-exec-and-x.html
http://tech.natemurray.com/2007/03/ruby-shell-commands.html
给出命令,例如attrib
我发现虽然这种方法不像以下那样令人难忘 . 系统(“命令”)或反引号中的命令,与其他方法相比,这种方法的一个好处是...反引号似乎没有让我'put'命令我运行/存储我想要在变量中运行的命令,而system(“thecommand”)似乎不让我得到输出 . 虽然这个方法允许我做这两件事,但它让我可以独立访问stdin,stdout和stderr .
https://blog.bigbinary.com/2012/10/18/backtick-system-exec-in-ruby.html
http://ruby-doc.org/stdlib-2.4.1/libdoc/open3/rdoc/Open3.html
我们可以通过多种方式实现它 .
使用
Kernel#exec
,执行此命令后不执行任何操作:使用
backticks or %x
使用
Kernel#system
命令,如果成功则返回true
,如果不成功则返回false
,如果命令执行失败则返回nil
:还有一个选择:
当你:
需要stderr以及stdout
可以't/won' t使用Open3 / Open4(他们在Mac上的NetBeans中抛出异常,不明白为什么)
您可以使用shell重定向:
从MS-DOS的早期开始,
2>&1
语法在Linux,Mac和Windows上工作 .这是我在Ruby中运行shell脚本的最佳文章:“6 Ways to Run Shell Commands in Ruby” .
如果你只需要输出使用反引号 .
我需要更高级的东西,如STDOUT和STDERR,所以我使用了Open4 gem . 你有解释的所有方法 .
使用这里的答案并在Mihai的答案中链接,我整理了一个满足这些要求的功能:
整齐地捕获STDOUT和STDERR,以便在从控制台运行脚本时它们不会"leak" .
允许将参数作为数组传递给shell,因此无需担心转义 .
捕获命令的退出状态,以便在发生错误时清除 .
作为奖励,在shell命令成功退出(0)并将任何内容放在STDOUT上的情况下,这个也将返回STDOUT . 以这种方式,它与
system
不同,后者在这种情况下只返回true
.代码如下 . 具体功能是
system_quietly
:我喜欢这样做的方法是使用
%x
文字,这使得在命令中使用引号变得容易(并且可读!),如下所示:在这种情况下,将使用当前目录下的所有测试文件填充文件列表,您可以按预期处理该文件:
不要忘记
spawn
命令来创建执行指定命令的后台进程 . 您甚至可以使用Process
类和返回的pid
等待其完成:该文档说:此方法类似于
#system
但它不等待命令完成 .不是一个真正的答案,但也许有人会觉得这很有用,而且就此而言 .
使用TK GUI时在Windows上,你需要从rubyw调用shell命令,你总会有一个恼人的cmd窗口弹出不到一秒钟 .
为了避免这种情况你可以使用
要么
两者都将ipconfig的输出存储在'log.txt'中,但是不会出现任何窗口 .
你需要在脚本中使用
require 'win32ole'
.使用TK和rubyw时,
system()
,exec()
和spawn()
都会弹出那个烦人的窗口 .我最喜欢的是Open3
您也可以使用反引号运算符(`),类似于Perl:
如果你需要简单的东西,很方便 .
您想要使用哪种方法取决于您要完成的内容;查看文档以获取有关不同方法的更多详细信息 .
上面的答案已经非常好了,但我真的想分享以下摘要文章:“6 Ways to Run Shell Commands in Ruby”
基本上,它告诉我们:
Kernel#exec
:system
和$?
:反引号(`):
IO#popen
:Open3#popen3
- stdlib:Open4#popen4
- 一颗宝石:这是我在OS X上的ruby脚本中使用的一个很酷的一个(这样我即使在从窗口切换后也可以启动脚本并获得更新):
如果你真的需要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
可能会有轻微的开销,您可能不会注意到 .最简单的方法是,例如:
这是基于this answer的流程图 . 另见,using script to emulate a terminal .
在这些机制之间进行选择时需要考虑的一些事项是:
你只想要stdout还是你还需要stderr?甚至分开了?
你的产量有多大?你想把整个结果保存在记忆中吗?
在子进程仍在运行时,是否要读取一些输出?
您需要结果代码吗?
您是否需要一个代表该进程的ruby对象并允许您按需杀死它?
你可能需要从简单的反引号(``),system()和
IO.popen
到完整的Kernel.fork
/Kernel.exec
以及IO.pipe
和IO.select
.如果子进程执行时间太长,您可能还希望将超时投入到混合中 .
不幸的是,它非常多 depends .
我绝对不是Ruby专家,但我会试一试:
您还应该能够执行以下操作:
如果你的案例比普通案例更复杂(无法用 ```` 处理),请查看
Kernel.spawn()
here . 这似乎是 stock Ruby 提供的执行外部命令的最通用/全功能 .例如 . 你可以用它来:
创建进程组(Windows)
重定向,输出,错误到文件/每个其他 .
设置env vars,umask
在执行命令之前更改dir
设置CPU / data /的资源限制
在其他答案中,可以使用其他选项完成所有操作,但需要更多代码 .
官方ruby documentation有足够好的例子 .