Ruby에서 쉘 명령 호출
Ruby 프로그램 내부에서 쉘 명령을 어떻게 호출합니까? 그런 다음이 명령의 출력을 Ruby로 다시 가져 오려면 어떻게해야합니까?
이 설명은 내 친구의 주석이 달린 Ruby 스크립트 를 기반으로합니다 . 스크립트를 개선하려면 링크에서 자유롭게 업데이트하십시오.
루비 쉘에게 호출 할 때 첫째, 주, 그것은 일반적으로 호출하는 /bin/sh
, 하지 배쉬. 일부 Bash 구문은 /bin/sh
모든 시스템에서 지원되지 않습니다 .
쉘 스크립트를 실행하는 방법은 다음과 같습니다.
cmd = "echo 'hi'" # Sample string that can be used
Kernel#`
, 일반적으로 백틱이라고합니다.`cmd`
이것은 Bash, PHP 및 Perl을 포함한 다른 많은 언어와 같습니다.
쉘 명령의 결과 (즉, 표준 출력)를 반환합니다.
문서 : http://ruby-doc.org/core/Kernel.html#method-i-60
value = `echo 'hi'` value = `#{cmd}`
내장 구문,
%x( cmd )
x
문자 뒤에는 어떤 문자도 될 수있는 구분 기호가 있습니다. 구분 기호는 문자 중 하나 인 경우(
,[
,{
, 또는<
, 문자 그대로 중첩 구분 쌍을 고려하여, 일치하는 닫는 구분 기호까지의 문자로 구성되어 있습니다. 다른 모든 구분 기호의 경우 리터럴은 구분 기호 문자의 다음 발생까지 문자로 구성됩니다. 문자열 보간#{ ... }
이 허용됩니다.백틱처럼 쉘 명령의 결과 (즉, 표준 출력)를 반환합니다.
문서 : http://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html
value = %x( echo 'hi' ) value = %x[ #{cmd} ]
Kernel#system
서브 쉘에서 주어진 명령을 실행합니다.
true
명령이 발견되고 성공적으로 실행되면 반환 하고,false
그렇지 않으면 반환합니다.문서 : http://ruby-doc.org/core/Kernel.html#method-i-system
wasGood = system( "echo 'hi'" ) wasGood = system( cmd )
Kernel#exec
주어진 외부 명령을 실행하여 현재 프로세스를 대체합니다.
없음을 반환하면 현재 프로세스가 대체되고 계속되지 않습니다.
문서 : http://ruby-doc.org/core/Kernel.html#method-i-exec
exec( "echo 'hi'" ) exec( cmd ) # Note: this will never be reached because of the line above
다음은 몇 가지 추가 조언입니다 $?
같은 인 $CHILD_STATUS
, 당신은 역 따옴표를 사용하는 경우 마지막 시스템 실행 된 명령의 상태를 액세스, system()
또는 %x{}
. 그런 다음 exitstatus
및 pid
속성에 액세스 할 수 있습니다 .
$?.exitstatus
자세한 내용은 다음을 참조하십시오.
- http://www.elctech.com/blog/im-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
이 답변을 기반으로 한 순서도는 다음과 같습니다 . using script
to emulate a terminal을 참조하십시오 .
이 작업을 수행하는 방법은 %x
리터럴을 사용하는 것이므로 다음과 같이 명령에서 따옴표를 쉽게 사용할 수 있습니다 (읽을 수 있습니다!).
directorylist = %x[find . -name '*test.rb' | sort]
이 경우 예상대로 처리 할 수있는 현재 디렉터리 아래의 모든 테스트 파일로 파일 목록을 채 웁니다.
directorylist.each do |filename|
filename.chomp!
# work with file
end
다음은 Ruby에서 쉘 스크립트를 실행하는 것에 대한 제 생각에 가장 좋은 기사입니다 : " Ruby에서 쉘 명령을 실행하는 6 가지 방법 ".
출력 만 얻으려면 백틱을 사용하십시오.
STDOUT 및 STDERR과 같은 고급 기능이 필요했기 때문에 Open4 gem을 사용했습니다. 거기에 모든 방법이 설명되어 있습니다.
내가 가장 좋아하는 것은 Open3
require "open3"
Open3.popen3('nroff -man') { |stdin, stdout, stderr| ... }
이러한 메커니즘 중에서 선택할 때 고려해야 할 사항은 다음과 같습니다.
- stdout을 원합니까 아니면 stderr도 필요합니까? 또는 분리?
- 당신의 출력은 얼마나 큽니까? 전체 결과를 메모리에 저장 하시겠습니까?
- 하위 프로세스가 실행되는 동안 일부 출력을 읽으시겠습니까?
- 결과 코드가 필요합니까?
- 프로세스를 표현하고 필요에 따라 종료 할 수있는 루비 객체가 필요합니까?
간단한 백틱 (``), system () 및 IO.popen
본격적인 Kernel.fork
/ Kernel.exec
with IO.pipe
and IO.select
.
하위 프로세스를 실행하는 데 너무 오래 걸리는 경우 시간 초과를 혼합에 추가 할 수도 있습니다.
불행하게도, 그것은 매우 많이 의존한다 .
하나 더 옵션 :
때를:
- stdout뿐만 아니라 stderr이 필요합니다.
- Open3 / Open4를 사용할 수 없거나 사용할 수 없습니다 (Mac의 NetBeans에서 예외가 발생합니다. 이유를 알 수 없음)
셸 리디렉션을 사용할 수 있습니다.
puts %x[cat bogus.txt].inspect
=> ""
puts %x[cat bogus.txt 2>&1].inspect
=> "cat: bogus.txt: No such file or directory\n"
이 2>&1
구문 은 MS-DOS 초기부터 Linux , Mac 및 Windows 에서 작동합니다 .
저는 확실히 Ruby 전문가는 아니지만 한번 시도해 보겠습니다.
$ irb
system "echo Hi"
Hi
=> true
또한 다음과 같은 작업을 수행 할 수 있어야합니다.
cmd = 'ls'
system(cmd)
위의 답변은 이미 상당히 훌륭하지만 다음 요약 기사를 공유하고 싶습니다. " Ruby에서 쉘 명령을 실행하는 6 가지 방법 "
기본적으로 다음과 같이 알려줍니다.
Kernel#exec
:
exec 'echo "hello $HOSTNAME"'
system
및 $?
:
system 'false'
puts $?
백틱 (`) :
today = `date`
IO#popen
:
IO.popen("date") { |f| puts f.gets }
Open3#popen3
-stdlib :
require "open3"
stdin, stdout, stderr = Open3.popen3('dc')
Open4#popen4
-보석 :
require "open4"
pid, stdin, stdout, stderr = Open4::popen4 "false" # => [26327, #<IO:0x6dff24>, #<IO:0x6dfee8>, #<IO:0x6dfe84>]
Bash가 정말로 필요한 경우 "최상"답변의 메모에 따라.
루비 쉘에게 호출 할 때 첫째, 주, 그것은 일반적으로 호출하는
/bin/sh
, 하지 배쉬. 일부 Bash 구문은/bin/sh
모든 시스템에서 지원되지 않습니다 .
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
눈치 채지 못할 것입니다.
Perl과 유사한 백틱 연산자 (`)를 사용할 수도 있습니다.
directoryListing = `ls /`
puts directoryListing # prints the contents of the root directory
간단한 것이 필요한 경우 편리합니다.
사용하려는 방법은 수행하려는 작업에 따라 다릅니다. 다른 방법에 대한 자세한 내용은 문서를 확인하십시오.
가장 쉬운 방법은 다음과 같습니다.
reboot = `init 6`
puts reboot
여기에 답변을 사용하고 Mihai의 답변에 링크 된 것을 사용하여 다음 요구 사항을 충족하는 기능을 모았습니다.
- 내 스크립트가 콘솔에서 실행될 때 "누출"되지 않도록 STDOUT 및 STDERR을 깔끔하게 캡처합니다.
- 인수가 배열로 셸에 전달되도록 허용하므로 이스케이프에 대해 걱정할 필요가 없습니다.
- 명령의 종료 상태를 캡처하여 오류가 발생했을 때 명확하게합니다.
보너스로 이것은 쉘 명령이 성공적으로 종료되고 (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"
우리는 여러 가지 방법으로 그것을 달성 할 수 있습니다.
를 사용하면 Kernel#exec
이 명령이 실행 된 후에는 아무것도 없습니다.
exec('ls ~')
사용 backticks or %x
`ls ~`
=> "Applications\nDesktop\nDocuments"
%x(ls ~)
=> "Applications\nDesktop\nDocuments"
Using Kernel#system
command, returns true
if successful, false
if unsuccessful and returns nil
if command execution fails:
system('ls ~')
=> true
Don't forget the spawn
command to create a background process to execute the specified command. You can even wait for its completion using the Process
class and the returned pid
:
pid = spawn("tar xf ruby-2.0.0-p195.tar.bz2")
Process.wait pid
pid = spawn(RbConfig.ruby, "-eputs'Hello, world!'")
Process.wait pid
The doc says: This method is similar to #system
but it doesn't wait for the command to finish.
If you have a more complex case than the common case (that can not be handled with ``
) then check out Kernel.spawn()
here. This seems to be the most generic/full-featured provided by stock Ruby to execute external commands.
E.g. you can use it to:
- create process groups (Windows)
- redirect in, out, error to files/each-other.
- set env vars, umask
- change dir before executing command
- set resource limits for CPU/data/...
- Do everything that can be done with other options in other answers, but with more code.
Official ruby documentation has good enough examples.
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)
backticks ` method is the easiest one to call shell commands from ruby. It returns the result of the shell command.
url_request = 'http://google.com' result_of_shell_command = `curl #{url_request}`
Given a command eg attrib
require 'open3'
a="attrib"
Open3.popen3(a) do |stdin, stdout, stderr|
puts stdout.read
end
I've found that while this method isn't as memorable as e.g. system("thecommand") or thecommand in backticks, a good thing about this method compared to other methods.. is e.g. backticks doesn't seem to let me 'puts' the command I run / store the command I want to run in a variable, and system("thecommand") doesn't seem to let me get the output. Whereas this method lets me do both of those things, and it lets me access stdin, stdout and stderr independently.
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
Not really an answer but maybe someone will find this useful, and its regarding to this.
Windows에서 TK GUI를 사용할 때 rubyw에서 쉘 명령을 호출해야 할 때, u는 항상 성가신 cmd 창이 1 초 미만 동안 팝업됩니다.
이것을 피하려면 사용할 수 있습니다
WIN32OLE.new('Shell.Application').ShellExecute('ipconfig > log.txt','','','open',0)
또는
WIN32OLE.new('WScript.Shell').Run('ipconfig > log.txt',0,0)
둘 다 ipconfig의 출력을 'log.txt'에 저장하지만 창이 나타나지 않습니다.
U는 require 'win32ole'
스크립트 내부에 필요합니다 .
system()
, exec()
그리고 spawn()
TK와 rubyw를 사용할 때 모두 성가신 창을 띄울 것입니다.
다음은 OS X의 루비 스크립트에서 사용하는 멋진 것입니다 (스크립트를 시작하고 창에서 전환 한 후에도 업데이트를받을 수 있습니다).
cmd = %Q|osascript -e 'display notification "Server was reset" with title "Posted Update"'|
system ( cmd )
참고 URL : https://stackoverflow.com/questions/2232/calling-shell-commands-from-ruby
'Nice programing' 카테고리의 다른 글
객체에 JavaScript의 키가 있는지 어떻게 확인합니까? (0) | 2020.09.27 |
---|---|
.gitignore 파일을 만드는 방법 (0) | 2020.09.27 |
SQL IN 절 매개 변수화 (0) | 2020.09.27 |
함수 실행에 걸리는 시간을 측정하는 방법 (0) | 2020.09.27 |
선택 상자의 모든 옵션을 제거한 다음 하나의 옵션을 추가하고 jQuery로 선택하는 방법은 무엇입니까? (0) | 2020.09.27 |