[ruby] Ruby에서 쉘 명령을 호출하는 방법

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



답변

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

먼저 Ruby가 쉘을 호출 할 때 일반적으로 /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문자 뒤에는 분리 문자가 있으며, 이는 임의의 문자 일 수 있습니다. 구분 기호는 문자 중 하나 인 경우 (, [, {, 또는 <, 문자 그대로 중첩 구분 쌍을 고려하여, 일치하는 닫는 구분 기호까지의 문자로 구성되어 있습니다. 다른 모든 구분 기호의 경우 리터럴은 다음에 나오는 구분 기호 문자까지의 문자로 구성됩니다. 문자열 보간 #{ ... }이 허용됩니다.

    백틱과 마찬가지로 쉘 명령의 결과 (예 : 표준 출력)를 반환합니다.

    문서 : 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{}. 그런 다음 exitstatuspid속성에 액세스 할 수 있습니다 .

$?.exitstatus

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


답변


답변

내가 좋아하는 방법은 %x리터럴을 사용하여 명령에서 따옴표를 사용하는 것이 쉽고 읽기 쉽습니다.

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

이 경우 현재 디렉토리 아래의 모든 테스트 파일로 파일 목록을 채우고 예상대로 처리 할 수 ​​있습니다.

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


답변

루비에서 쉘 스크립트를 실행하는 것에 대한 제 의견으로는 ” 루비에서 쉘 명령을 실행하는 6 가지 방법 “이 있습니다.

출력 만 가져 오려면 백틱을 사용하십시오.

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


답변

내가 가장 좋아하는 것은 Open3

  require "open3"

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


답변

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

  1. 당신은 stdout을 원합니까 아니면 stderr도 필요합니까? 아니면 심지어 분리?
  2. 출력이 얼마나 큽니까? 전체 결과를 메모리에 저장 하시겠습니까?
  3. 서브 프로세스가 여전히 실행 중일 때 일부 출력을 읽으시겠습니까?
  4. 결과 코드가 필요하십니까?
  5. 프로세스를 나타내는 Ruby 객체가 필요하고 필요할 때 프로세스를 종료 할 수 있습니까?

당신은 (“), 간단한 역 따옴표에서 아무것도해야 할 수도 있습니다 system(), 그리고 IO.popen날려-전체에 Kernel.fork/ Kernel.execIO.pipeIO.select.

하위 프로세스를 실행하는 데 시간이 너무 오래 걸리면 믹스에 타임 아웃을 던질 수도 있습니다.

불행히도, 그것은 매우 달려 있습니다.


답변

하나 더 옵션 :

때를:

  • stdout뿐만 아니라 stderr 필요
  • 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 에서 작동합니다 .