programing

Ruby에서 셸 명령을 호출하는 방법

mailnote 2023. 6. 15. 22:01
반응형

Ruby에서 셸 명령을 호출하는 방법

루비 프로그램 내부에서 셸 명령을 호출하려면 어떻게 해야 합니까?그런 다음 이 명령의 출력을 루비로 다시 가져오려면 어떻게 해야 합니까?

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

첫째, 루비가 셸을 호출할 때 일반적으로 호출합니다./bin/shBash가 아닙니다.일부 Bash 구문은 에서 지원되지 않습니다./bin/sh모든 시스템에서.

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

cmd = "echo 'hi'" # Sample string that can be used
  1. Kernel#`이라고 불리는 것은 – 일적으백고라합니다이트릭로반합▁commonly니다고▁back▁–라.`cmd`

    이것은 Bash, PHP, Perl을 포함한 많은 다른 언어들과 같습니다.

    셸 명령의 결과(즉, 표준 출력)를 반환합니다.

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

    value = `echo 'hi'`
    value = `#{cmd}`
    
  2. 구문, 기본제구문공,,%x( cmd )

    x문자는 임의의 문자일 수 있는 구분 기호입니다.(,[,{또는<리터럴은 중첩된 구분 기호 쌍을 고려하여 일치하는 닫는 구분 기호까지 문자로 구성됩니다.다른 모든 구분 기호의 경우 리터럴은 다음 구분 기호 문자까지 문자로 구성됩니다.#{ ... }허용됩니다.

    백스틱과 마찬가지로 셸 명령의 결과(즉, 표준 출력)를 반환합니다.

    문서: https://docs.ruby-lang.org/en/master/syntax/literals_rdoc.html#label-Percent+Strings

    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

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

다음은 "Ruby에서 하위 프로세스를 시작하는 방법을 사용할 "를 기준으로 한 흐름도입니다.참고 항목: "응용 프로그램의 stdout이 파이프가 아닌 터미널이라고 생각하도록 프로그램을 속입니다."

enter image description here

은 제가좋방은법을 입니다.%x리터럴을 사용하면 명령어에서 따옴표를 쉽게 사용할 수 있습니다. 예를 들어 다음과 같습니다.

directorylist = %x[find . -name '*test.rb' | sort]

이 경우 파일 목록은 현재 디렉터리 아래의 모든 테스트 파일로 채워지며, 예상대로 처리할 수 있습니다.

directorylist.each do |filename|
  filename.chomp!
  # work with file
end

루비에서 셸 스크립트를 실행하는 것에 대한 제 의견 중 최고의 기사는 "루비에서 셸 명령을 실행하는 6가지 방법"입니다.

출력만 가져오면 되는 경우 백택스를 사용합니다.

STDOUT, STDERR 등 좀 더 고급스러운 것들이 필요해서 Open4 보석을 사용했습니다.모든 방법이 설명되어 있습니다.

제가 가장 좋아하는 은 Open3입니다.

  require "open3"

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

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

  1. 당신은 그냥 stdout을 원합니까 아니면 stderr도 필요합니까?아니면 따로따로?
  2. 생산량이 얼마나 됩니까?전체 결과를 메모리에 저장하시겠습니까?
  3. 하위 프로세스가 실행 중인 동안 일부 출력을 읽으시겠습니까?
  4. 결과 코드가 필요합니까?
  5. 프로세스를 대표하고 요청 시 삭제할 수 있는 Ruby 객체가 필요합니까?

간단한 백트릭('')부터 무엇이든 필요할 수 있습니다.system(),그리고.IO.popenKernel.fork/Kernel.exec와 함께IO.pipe그리고.IO.select.

하위 프로세스를 실행하는 데 시간이 너무 오래 걸리는 경우 시간 초과를 혼합물에 추가할 수도 있습니다.

불행하게도, 그것은 매우 의존적입니다.

저는 확실히 루비 전문가는 아니지만 시도해 보겠습니다.

$ irb 
system "echo Hi"
Hi
=> true

또한 다음과 같은 작업을 수행할 수 있어야 합니다.

cmd = 'ls'
system(cmd)

옵션 하나 더:

다음과 같은 경우:

  • 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에서 셸 명령을 실행하는 6가지 방법"이라는 요약 기사를 공유하고 싶습니다.

기본적으로, 다음과 같은 것을 알려줍니다.

Kernel#exec:

exec 'echo "hello $HOSTNAME"'

system그리고.$?:

system 'false' 
puts $?

백스틱('):

today = `date`

IO#popen:

IO.popen("date") { |f| puts f.gets }

Open3#popen3stdlib:

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/shBash가 아닙니다.일부 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")

루비는 셰방을 존중해야 하지만 당신은 항상 사용할 수 있습니다.

system("bash ./my_script.sh")

확실히 하기 위해, 비록 약간의 간접비가 있을지라도./bin/sh달리는 /bin/bash아마 눈치채지 못할 겁니다

Perl과 유사한 백틱 연산자(')를 사용할 수도 있습니다.

directoryListing = `ls /`
puts directoryListing # prints the contents of the root directory

간단한 것이 필요하면 편리합니다.

사용할 방법은 수행하려는 작업에 따라 달라집니다. 다양한 방법에 대한 자세한 내용은 문서를 참조하십시오.

여기에 있는 답변과 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 and 자과귀순계.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하지만 명령이 끝날 때까지 기다리지는 않습니다.

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

reboot = `init 6`
puts reboot

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")

또는

`thecommand`

백스틱에서, 다른 방법과 비교하여 이 방법의 좋은 점은 백스틱이 나를 허락하지 않는 것처럼 보인다는 것입니다.puts run I 및 "/run" 명령어를 입력합니다.system("thecommand")이 방법은 제가 출력을 얻을 수 있게 해주지 않는 반면에 이 두 가지를 모두 할 수 있게 해주며, 제가 stdin, stdout 및 stderr에 독립적으로 액세스할 수 있게 해줍니다.

"Ruby에서 명령 실행" Ruby의 Open3 설명서를 참조하십시오.

더 경우가 할 수 입니다.``그리고 나서 체크아웃합니다.이것은 주식 Ruby가 외부 명령을 실행하기 위해 제공하는 가장 일반적인/완전한 기능인 것 같습니다.

다음 용도로 사용할 수 있습니다.

  • 프로세스 그룹 생성(윈도우즈).
  • 오류를 파일/서로 리디렉션합니다.
  • 변수 설정, 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)

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

Windows에서 TK GUI를 사용하고 Rubyw에서 셸 명령을 호출해야 하는 경우 항상 짜증나는 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창이 안나오거든요.

은 ▁you 필요할 입니다.require 'win32ole'스크립트 안에 있습니다.

system(),exec()그리고.spawn()TK와 루비를 사용할 때 짜증나는 창이 나타납니다.

셸 명령에 대해 잘 모르겠습니다.시스템 명령의 출력을 변수 값으로 캡처하는 데 다음을 사용했습니다.

val = capture(:stdout) do
  system("pwd")
end

puts val

단축 버전:

val = capture(:stdout) { system("pwd") }

캡처 방법은 active_support/core_ext/context/capture.method를 통해 제공됩니다.

도 마가지 오캡수 있할다니습으로 할 수 .:stderr

OS X의 루비 스크립트에서 사용하는 멋진 스크립트는 다음과 같습니다(창에서 전환한 후에도 스크립트를 시작하고 업데이트를 받을 수 있습니다).

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

사용할 수 있습니다.format일부 정보를 인쇄하는 방법은 다음과 같습니다.

puts format('%s', `ps`)
puts format('%d MB', (`ps -o rss= -p #{Process.pid}`.to_i / 1024))

언급URL : https://stackoverflow.com/questions/2232/how-to-call-shell-commands-from-ruby

반응형