Ruby에서 Kernel # system 을 사용하여 명령을 호출하면 어떻게 출력합니까?
system("ls")
답변
혼돈의 대답 을 조금 확장하고 명확하게하고 싶습니다 .
명령을 백틱으로 둘러싼 경우 system ()을 전혀 호출 할 필요가 없습니다. 백틱은 명령을 실행하고 출력을 문자열로 반환합니다. 그런 다음 값을 다음과 같이 변수에 할당 할 수 있습니다.
output = `ls`
p output
또는
printf output # escapes newline chars
답변
당신이 사용자 제공 값을 포함하는 문자열을 전달하는 모든 솔루션주의하십시오 system
, %x[]
등 안전하지! 실제로 안전하지 않은 의미 : 사용자가 컨텍스트에서 프로그램의 모든 권한으로 실행되도록 코드를 트리거 할 수 있습니다.
내가 말할 수있는 한 system
와 Open3.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
, capture2e
및 capture3
작업 같은 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`
