문제

Ruby 프로그램 내부에서 쉘 명령을 어떻게 호출하나요?그런 다음 이 명령의 출력을 어떻게 Ruby로 다시 가져오나요?

도움이 되었습니까?

해결책

이 설명은 댓글을 기반으로 합니다. 루비 스크립트 내 친구에게서.스크립트를 개선하려면 링크에서 자유롭게 업데이트하세요.

먼저, Ruby가 셸을 호출할 때 일반적으로 다음을 호출한다는 점에 유의하세요. /bin/sh, ~ 아니다 세게 때리다.일부 Bash 구문은 다음에서 지원되지 않습니다. /bin/sh 모든 시스템에서.

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

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 문자는 구분 기호이며 모든 문자가 될 수 있습니다.구분 기호가 문자 중 하나인 경우 (, [, {, 또는 <, 문자 그럴은 중첩 된 구분 기호 쌍을 고려하여 일치 폐쇄 구분 기호까지 문자로 구성됩니다.다른 모든 구분자의 경우, 리터럴은 다음으로 Delimiter 캐릭터의 발생까지 캐릭터를 구성합니다.문자열 보간 #{ ... } 허용됩니다.

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

    문서: http://www.ruby-doc.org/docs/ProgrammingRuby/html/언어.html

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

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

    보고 true 명령을 찾아서 성공적으로 실행한 경우 false 그렇지 않으면.

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

    wasGood = system( "echo 'hi'" )
    wasGood = system( cmd )
    
  4. 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

자세한 내용은 다음을 참조하세요.

다른 팁

다음은 다음을 기반으로 한 흐름도입니다. 이 답변.또한보십시오, 사용하여 script 터미널을 에뮬레이트하려면.

enter image description here

내가 좋아하는 방식은 다음을 사용하는 것입니다. %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을 사용했습니다.거기에 모든 방법이 설명되어 있습니다.

내가 가장 좋아하는 것은 오픈3

  require "open3"

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

이러한 메커니즘 중에서 선택할 때 고려해야 할 몇 가지 사항은 다음과 같습니다.

  1. 당신은 단지 stdout을 원합니까, 아니면 stderr도 필요합니까?아니면 심지어 분리 되었습니까?
  2. 당신의 생산량은 얼마나 됩니까?전체 결과를 메모리로 유지하고 싶습니까?
  3. 하위 프로세스가 여전히 실행중인 동안 일부 출력을 읽고 싶습니까?
  4. 결과 코드가 필요합니까?
  5. 프로세스를 나타내는 루비 객체가 필요하고 주문시를 죽일 수 있습니까?

간단한 역따옴표(``), system() 등 무엇이든 필요할 수 있습니다. IO.popen 본격적으로 Kernel.fork/Kernel.exec ~와 함께 IO.pipe 그리고 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 초기부터.

저는 확실히 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 -- 표준 라이브러리:

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가 정말로 필요하다면 "최고의" 답변에 있는 참고 사항을 따르십시오.

먼저, Ruby가 셸을 호출할 때 일반적으로 다음을 호출한다는 점에 유의하세요. /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")) 루비 ~해야 한다 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의 답변에 연결된 답변을 사용하여 다음 요구 사항을 충족하는 기능을 구성했습니다.

  1. STDOUT 및 STDERR을 깔끔하게 캡처하여 콘솔에서 스크립트를 실행할 때 "누출"되지 않습니다.
  2. 인수가 배열로 셸에 전달되도록 허용하므로 이스케이프에 대해 걱정할 필요가 없습니다.
  3. 오류가 발생한 경우 명확하도록 명령의 종료 상태를 캡처합니다.

보너스로 이것은 쉘 명령이 성공적으로 종료되고(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"

사용 Kernel#system 명령, 반환 true 성공하면, false 실패하고 돌아오면 nil 명령 실행이 실패하는 경우:

system('ls ~')
=> true

잊지 마세요 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.spawn() 여기.이것은 다음에서 제공하는 가장 일반적인/모든 기능을 갖춘 것 같습니다. 재고 루비 외부 명령을 실행합니다.

예:다음과 같은 용도로 사용할 수 있습니다.

  • 프로세스 그룹 생성(Windows)
  • 안으로, 밖으로, 오류를 파일/서로 리디렉션합니다.
  • 환경 변수, umask 설정
  • 명령을 실행하기 전에 디렉토리를 변경하십시오
  • CPU/데이터/...에 대한 리소스 제한을 설정합니다.
  • 다른 답변의 다른 옵션으로 수행할 수 있는 모든 작업을 수행하되 더 많은 코드를 사용하십시오.

공식적인 루비 문서 충분히 좋은 예가 있습니다.

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에서 쉘 명령을 호출하는 가장 쉬운 방법입니다.쉘 명령의 결과를 반환합니다.

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

주어진 명령(예: attrib)

require 'open3'

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

나는 이 방법이 예를 들어 기억에 남지 않는다는 것을 발견했습니다.system("thecommand") 또는 백틱 안의 명령은 다른 방법에 비해 이 방법이 좋은 점입니다.예를 들어백틱을 사용하면 내가 실행하는 명령을 '넣거나' 실행하려는 명령을 변수에 저장할 수 없는 것 같고, 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

실제로 대답은 아니지만 누군가가 이것이 유용하다고 생각할 수도 있습니다.

Windows에서 TK GUI를 사용하고 rubyw에서 쉘 명령을 호출해야 할 때, 항상 1초도 안 되는 시간 동안 성가신 cmd 창이 팝업됩니다.

이를 방지하려면 다음을 사용할 수 있습니다.

WIN32OLE.new('Shell.Application').ShellExecute('ipconfig > log.txt','','','open',0)

또는

WIN32OLE.new('WScript.Shell').Run('ipconfig > log.txt',0,0)

둘 다 ipconfig의 출력을 'log.txt' 안에 저장하지만 창이 나타나지 않습니다.

당신은해야 할 것입니다 require 'win32ole' 스크립트 내부.

system(), exec() 그리고 spawn() TK와 Rubyw를 사용할 때 모두 짜증나는 창이 나타날 것입니다.

다음은 OS X의 Ruby 스크립트에서 사용하는 멋진 기능입니다(창에서 전환한 후에도 스크립트를 시작하고 업데이트를 받을 수 있도록).

cmd = %Q|osascript -e 'display notification "Server was reset" with title "Posted Update"'|
system ( cmd )
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top