ruby 코드 루비에서 쉘 명령 호출하기




루비 코드 (16)

Ruby 프로그램 내부에서 셸 명령을 호출하려면 어떻게해야합니까? 그런 다음이 명령의 출력을 다시 Ruby로 가져 오는 방법은 무엇입니까?


실제로 대답은 아니지만 어쩌면 누군가가 유용 할 것입니다.

Windows에서 TK GUI를 사용할 때 ruby에서 쉘 명령을 호출해야 할 때 u는 항상 초당 적게 나타나는 성가신 cmd 창이 있습니다.

이걸 피하려면

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'require 'win32ole' 해야합니다.

system() , exec() , spawn() 은 모두 TK와 rubyw를 사용할 때 그 성가신 창을 팝업합니다.


하나 더 옵션 :

때를:

  • stderr와 stdout이 필요하다.
  • Open3 / Open4를 사용할 수 없거나 사용할 수 없습니다 (Mac에서 NetBeans의 예외를 throw합니다. 이유는 알 수 없습니다)

셸 리디렉션을 사용할 수 있습니다.

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 에서 작동합니다.


주어진 명령 예 attrib

require 'open3'

a="attrib"
Open3.popen3(a) do |stdin, stdout, stderr|
  puts stdout.read
end

나는이 방법이 예를 들어 system ( "thecommand")이나 backticks의 thecommand처럼 기억에 남는 것은 아니지만 다른 방법과 비교할 때이 방법에 대한 좋은 점은 발견했다. backticks는 나를 'puts' '내가 실행하는 명령 / 변수에서 실행하려는 명령을 저장하고 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


가장 쉬운 방법은 다음과 같습니다.

reboot = `init 6`
puts reboot

다음은 Ruby에서 쉘 스크립트를 실행하는 것에 대한 필자의 의견으로는 " http://tech.natemurray.com/2007/03/ruby-shell-commands.html "입니다.

출력을 얻으려면 backticks를 사용해야합니다.

STDOUT 및 STDERR과 같은 고급 기능이 필요하므로 Open4 gem을 사용했습니다. 거기에 모든 방법이 설명되어 있습니다.


이러한 메커니즘을 선택할 때 고려해야 할 사항은 다음과 같습니다.

  1. stdout을 원하십니까? 아니면 stderr도 필요합니까? 심지어 분리 되었습니까?
  2. 출력은 얼마나 큽니까? 전체 결과를 메모리에 보관 하시겠습니까?
  3. 하위 프로세스가 실행 중일 때 일부 출력을 읽으려고합니까?
  4. 결과 코드가 필요합니까?
  5. 프로세스를 나타내는 루비 객체가 필요하고 필요에 따라 그것을 죽일 수 있습니까?

간단한 backticks (``), system (), IO.popen 에서부터 IO.pipeIO.select Kernel.fork / Kernel.exec 가 필요합니다.

하위 프로세스가 실행하는 데 너무 오래 걸리면, 타임 아웃을 믹스에 넣을 수도 있습니다.

불행히도, 그것은 매우 의존 합니다.


이 설명은 내 친구의 Ruby 스크립트 에 기반하고 있습니다. 스크립트를 개선하려면 링크에서 자유롭게 업데이트하십시오.

먼저 Ruby가 쉘로 호출 할 때 일반적으로 Bash가 아니라 /bin/sh 를 호출한다는 점에 유의하십시오. 모든 시스템에서 /bin/sh 는 일부 Bash 구문을 지원하지 않습니다.

쉘 스크립트를 실행하는 방법은 다음과 같습니다.

cmd = "echo 'hi'" # Sample string that can be used
  1. Kernel#` , 일반적으로 백틱이라고 부름 `cmd`

    이것은 Bash, PHP 및 Perl을 비롯한 많은 다른 언어와 유사합니다.

    쉘 명령의 결과를 리턴합니다.

    문서 도구 : http://ruby-doc.org/core/Kernel.html#method-i-60

    value = `echo 'hi'`
    value = `#{cmd}`
    
  2. 내장 구문, %x( cmd )

    x 문자 다음에 구분 기호가 있으며, 문자는 임의의 문자가 될 수 있습니다. 구분 기호가 문자 ( , [ , { 또는 < 중 하나 인 경우 리터럴은 중첩 된 구분 기호 쌍을 고려하여 일치하는 닫기 구분 기호까지의 문자로 구성됩니다. 다른 모든 구분 문자의 경우 리터럴은 다음에 분리 문자가 나옵니다. 문자열 보간 #{ ... } 이 허용됩니다.

    백틱과 마찬가지로 쉘 명령의 결과를 리턴합니다.

    문서 도구 : http://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html

    value = %x( echo 'hi' )
    value = %x[ #{cmd} ]
    
  3. Kernel#system

    서브 쉘에서 주어진 명령을 실행합니다.

    명령이 발견되어 성공적으로 실행되면 false 반환하고 그렇지 않으면 false 반환합니다.

    문서 도구 : http://ruby-doc.org/core/Kernel.html#method-i-system

    wasGood = system( "echo 'hi'" )
    wasGood = system( cmd )
    
  4. Kernel#exec

    주어진 외부 명령을 실행하여 현재 프로세스를 대체합니다.

    none을 반환하면 현재 프로세스가 대체되고 계속되지 않습니다.

    문서 도구 : 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 와 동일하며 backticks, system() 또는 %x{} 를 사용하는 경우 마지막 시스템 실행 명령의 상태에 액세스합니다. 그런 다음 exitstatuspid 속성에 액세스 할 수 있습니다.

$?.exitstatus

자세한 내용은 다음을 참조하십시오.


다음은 멋진 스크립트 중 하나입니다. OS X의 루비 스크립트에서 (스크립트를 시작하고 창을 닫은 후에도 업데이트를받을 수 있도록)

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

나는 확실히 Ruby 전문가는 아니지만 나는 그것을 한 번 제공 할 것이다.

$ irb 
system "echo Hi"
Hi
=> true

또한 다음과 같은 일을 할 수 있어야합니다 :

cmd = 'ls'
system(cmd)

이 대답을 기반으로 한 순서도가 있습니다. script 를 사용하여 터미널을 에뮬레이트하십시오 .


Mihai의 답변에서 링크 된 답변을 사용하여 다음 요구 사항을 충족하는 함수를 작성했습니다.

  1. 깔끔하게 STDOUT과 STDERR을 캡처하여 스크립트가 콘솔에서 실행될 때 "누출"하지 않습니다.
  2. 인수를 쉘로 배열로 전달할 수 있으므로 이스케이프 걱정을 할 필요가 없습니다.
  3. 명령의 종료 상태를 캡처하여 오류가 발생할 때를 알 수 있습니다.

보너스로 쉘 명령이 성공적으로 종료되고 (0) STDOUT에 아무 것도 올려 놓는 경우이 명령은 STDOUT을 반환합니다. 이런 식으로, 그것은 system 과 다르며, 그러한 경우에는 단순히 true 를 반환 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"

  • backticks`메소드는 루비에서 쉘 명령어를 호출하는 가장 쉬운 방법이다. 쉘 명령의 결과를 리턴합니다.

     url_request = 'http://google.com'
     result_of_shell_command = `curl #{url_request}`
    

내가 가장 좋아하는 것은 Open3

  require "open3"

  Open3.popen3('nroff -man') { |stdin, stdout, stderr| ... }

`` )로 처리 할 수없는 일반적인 경우보다 복잡한 경우에는 here 에서 Kernel.spawn() 을 체크 아웃 here . 이것은 외부 루틴 을 실행하기 위해 주식 Ruby 가 제공하는 가장 일반적인 / 완전한 기능인 것으로 보입니다.

예를 들어 다음과 같이 사용할 수 있습니다.

  • 프로세스 그룹 작성 (Windows)
  • 파일 / 서로에 오류가 발생하거나 오류가 발생합니다.
  • env vars, umask를 설정하십시오
  • 명령을 실행하기 전에 dir을 변경하십시오.
  • CPU / 데이터 / 리소스에 대한 리소스 제한 설정
  • 다른 답변으로 다른 옵션을 사용하여 수행 할 수있는 모든 작업을 코드를 통해 수행하십시오.

공식적인 here 에는 충분한 예제가 있습니다.

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)

spawn 명령을 잊지 말고 지정된 명령을 실행하는 백그라운드 프로세스를 작성하십시오. Process 클래스와 반환 된 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

의사는 다음과 같이 말합니다.이 방법은 #system 과 비슷하지만 명령이 완료 될 때까지 기다리지 않습니다.


우리는 여러 가지 방법으로 그것을 달성 할 수 있습니다.

Kernel#exec 사용하면이 명령을 실행 한 후에 아무 것도 실행되지 않습니다.

exec('ls ~')

backticks or %x

`ls ~`
=> "Applications\nDesktop\nDocuments"
%x(ls ~)
=> "Applications\nDesktop\nDocuments"

Kernel#system 명령을 사용하여 성공하면 false 를 반환하고, 실패하면 false 를 반환하고 명령 실행에 실패하면 nil 반환합니다.

system('ls ~')
=> true




interop