[ruby] Ruby에서 system () 호출의 출력 얻기

Ruby에서 Kernel # system 을 사용하여 명령을 호출하면 어떻게 출력합니까?

system("ls")



답변

혼돈의 대답 을 조금 확장하고 명확하게하고 싶습니다 .

명령을 백틱으로 둘러싼 경우 system ()을 전혀 호출 할 필요가 없습니다. 백틱은 명령을 실행하고 출력을 문자열로 반환합니다. 그런 다음 값을 다음과 같이 변수에 할당 할 수 있습니다.

output = `ls`
p output

또는

printf output # escapes newline chars


답변

당신이 사용자 제공 값을 포함하는 문자열을 전달하는 모든 솔루션주의하십시오 system, %x[]등 안전하지! 실제로 안전하지 않은 의미 : 사용자가 컨텍스트에서 프로그램의 모든 권한으로 실행되도록 코드를 트리거 할 수 있습니다.

내가 말할 수있는 한 systemOpen3.popen3루비 1.8의 보안 / 탈출 변형을 제공 할. Ruby 1.9에서는 IO::popen배열도 허용합니다.

모든 옵션과 인수를 이러한 호출 중 하나에 배열로 전달하면됩니다.

종료 상태뿐만 아니라 결과도 필요한 경우 Open3.popen3:

require 'open3'
stdin, stdout, stderr, wait_thr = Open3.popen3('usermod', '-p', @options['shadow'], @options['username'])
stdout.gets(nil)
stdout.close
stderr.gets(nil)
stderr.close
exit_code = wait_thr.value

블록 형식은 stdin, stdout 및 stderr을 자동으로 닫습니다. 그렇지 않으면 명시 적 닫아야 합니다.

추가 정보 : Ruby에서 위생 쉘 명령 또는 시스템 호출 형성


답변

레코드에 대해서만 (출력 및 작업 결과)를 원할 경우 다음을 수행 할 수 있습니다.

output=`ls no_existing_file` ;  result=$?.success?


답변

올 바르고 확실하게이 작업을 수행 할 수있는 간단한 방법을 사용하는 것 Open3.capture2(), Open3.capture2e()또는Open3.capture3() .

신뢰할 수없는 데이터와 함께 사용하는 경우 루비의 백틱과 그 %x별명을 사용하는 것은 어떠한 상황 에서도 안전 하지 않습니다 . 그것은이다 위험한 , 평범하고 단순하게 :

untrusted = "; date; echo"
out = `echo #{untrusted}`                              # BAD

untrusted = '"; date; echo"'
out = `echo "#{untrusted}"`                            # BAD

untrusted = "'; date; echo'"
out = `echo '#{untrusted}'`                            # BAD

system기능은, 대조적으로, 제대로 인수를 탈출 올바르게 사용하는 경우 :

ret = system "echo #{untrusted}"                       # BAD
ret = system 'echo', untrusted                         # good

문제는 출력 대신 종료 코드를 반환하고 후자를 캡처하는 것이 복잡하고 어수선하다는 것입니다.

이 스레드에서 가장 좋은 답변은 지금까지 Open3을 언급했지만 작업에 가장 적합한 기능은 아닙니다. Open3.capture2, capture2ecapture3작업 같은 system,하지만 반환 두 개 또는 세 개의 인수 :

out, err, st = Open3.capture3("echo #{untrusted}")     # BAD
out, err, st = Open3.capture3('echo', untrusted)       # good
out_err, st  = Open3.capture2e('echo', untrusted)      # good
out, st      = Open3.capture2('echo', untrusted)       # good
p st.exitstatus

또 다른 언급 IO.popen(). 구문은 배열을 입력으로 원한다는 의미에서 서투른 것일 수 있지만 작동합니다.

out = IO.popen(['echo', untrusted]).read               # good

편의를 위해 다음 Open3.capture3()과 같은 함수를 래핑 할 수 있습니다 .

#
# Returns stdout on success, false on failure, nil on error
#
def syscall(*cmd)
  begin
    stdout, stderr, status = Open3.capture3(*cmd)
    status.success? && stdout.slice!(0..-(1 + $/.size)) # strip trailing eol
  rescue
  end
end

예:

p system('foo')
p syscall('foo')
p system('which', 'foo')
p syscall('which', 'foo')
p system('which', 'which')
p syscall('which', 'which')

다음을 산출합니다.

nil
nil
false
false
/usr/bin/which         <— stdout from system('which', 'which')
true                   <- p system('which', 'which')
"/usr/bin/which"       <- p syscall('which', 'which')


답변

어떤 종류의 결과가 필요한지에 따라 system () 또는 % x []를 사용할 수 있습니다.

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

>> s = system 'uptime'
10:56  up 3 days, 23:10, 2 users, load averages: 0.17 0.17 0.14
=> true
>> s.class
=> TrueClass
>> $?.class
=> Process::Status

반면 % x [..]는 명령 결과를 문자열로 저장합니다.

>> result = %x[uptime]
=> "13:16  up 4 days,  1:30, 2 users, load averages: 0.39 0.29 0.23\n"
>> p result
"13:16  up 4 days,  1:30, 2 users, load averages: 0.39 0.29 0.23\n"
>> result.class
=> String

제이 필드하여 블로그 게시물 […] 간부 % X 및 상세 사용 시스템의 차이점을 설명한다.


답변

인수를 이스케이프 해야하는 경우 Ruby 1.9에서 IO.popen 은 배열도 허용합니다.

p IO.popen(["echo", "it's escaped"]).read

이전 버전에서는 Open3.popen3 을 사용할 수 있습니다 .

require "open3"

Open3.popen3("echo", "it's escaped") { |i, o| p o.read }

stdin을 통과 해야하는 경우 1.9와 1.8에서 모두 작동합니다.

out = IO.popen("xxd -p", "r+") { |io|
    io.print "xyz"
    io.close_write
    io.read.chomp
}
p out # "78797a"


답변

백틱을 사용합니다.

`ls`