Ruby에서 시스템() 호출의 출력을 가져오는 중
루비에서 커널#시스템을 사용하여 명령을 호출하면 출력을 어떻게 얻을 수 있습니까?
system("ls")
저는 혼돈의 답을 조금 더 확대하고 명확히 하고 싶습니다.
명령어를 백택으로 둘러싸면 시스템()을 호출할 필요가 전혀 없습니다.백트릭은 명령을 실행하고 출력을 문자열로 반환합니다.그런 다음 다음과 같은 변수에 값을 할당할 수 있습니다.
output = `ls`
p output
또는
printf output # escapes newline chars
사용자가 포함된 문자열을 전달하는 모든 솔루션은 다음과 같은 값을 제공합니다.system,%x[]등은 안전하지 않습니다!안전하지 않음은 실제로 의미합니다. 사용자가 프로그램의 모든 권한으로 컨텍스트에서 실행되도록 코드를 트리거할 수 있습니다.
가 말할 수 은 내가말수있한는할한▁as▁only있는수가내▁far말할▁can.system그리고.Open3.popen3Ruby 1.8에서 보안/탈출 버전을 제공합니다.1.9 비루 1.에서IO::popen배열도 허용합니다.
이러한 호출 중 하나에 모든 옵션과 인수를 배열로 전달하기만 하면 됩니다.
뿐만 아니라 상 하 필 결 도 요 한 경 는 자 태고만사아뿐용니하라▁if경우▁want필▁use▁but▁you한▁probably요▁result▁to▁you▁status종▁the료▁exit▁also.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에서 sanitary shell 명령 또는 시스템 호출 형성
(출력 및 작동 결과) 두 가지를 모두 원하는 경우 기록을 위해 다음 작업을 수행할 수 있습니다.
output=`ls no_existing_file` ; result=$?.success?
이 작업을 정확하고 안전하게 수행하는 간단한 방법은 , 또는 를 사용하는 것입니다.
의 백스틱을 해서 하의용사는것을것그딱등지와루비▁using것.%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
또 다른 언급이 있습니다.구문은 입력으로 배열을 원한다는 점에서 서툴 수 있지만 다음과 같이 작동합니다.
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')
필요한 결과에 따라 시스템() 또는 %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
Jay Fields의 블로그 게시물은 시스템, exec 및 %x[...] 사용의 차이점을 자세히 설명합니다.
인수를 이스케이프해야 하는 경우 Ruby 1.9 IO.popen에서도 배열을 허용합니다.
p IO.popen(["echo", "it's escaped"]).read
이전 버전에서는 Open3.open3을 사용할 수 있습니다.
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`
다른 방법은 다음과 같습니다.
f = open("|ls")
foo = f.read()
열려 있는 "ls" 앞에 있는 "파이프" 문자입니다.이 기능은 프로그램 표준 입력에 데이터를 공급하고 표준 출력을 읽는 데도 사용할 수 있습니다.
반환 값이 필요한 경우 다음과 같은 것이 유용하다는 것을 알게 되었습니다.
result = %x[ls]
puts result
나는 특히 내 컴퓨터에 있는 모든 Java 프로세스의 pid를 나열하고 싶었고, 다음을 사용했습니다.
ids = %x[ps ax | grep java | awk '{ print $1 }' | xargs]
Simon Hürlimann이 이미 설명했듯이 Open3는 백트릭 등보다 안전합니다.
require 'open3'
output = Open3.popen3("ls") { |stdin, stdout, stderr, wait_thr| stdout.read }
블록 양식은 stdin, stdout 및 stderr을 자동으로 닫힙니다. 그렇지 않으면 명시적으로 닫아야 합니다.
백스틱이나 팝업을 사용하는 것이 실제로 원하는 경우가 많지만 실제로는 질문에 대한 대답이 되지 않습니다.캡처하는 데는 타당한 이유가 있을 수 있습니다.system출력(자동화된 테스트용일 수 있음)약간의 구글링이 제가 다른 사람들의 이익을 위해 여기에 게시할 것이라고 생각하는 답변을 찾았습니다.
이 예제를 테스트하기 위해 필요했기 때문에 블록 설정을 사용하여 실제 이후의 표준 출력을 캡처합니다.system호출이 테스트 중인 코드에 묻혀 있습니다.
require 'tempfile'
def capture_stdout
stdout = $stdout.dup
Tempfile.open 'stdout-redirect' do |temp|
$stdout.reopen temp.path, 'w+'
yield if block_given?
$stdout.reopen stdout
temp.read
end
end
이 메서드는 실제 데이터를 저장하기 위해 임시 파일을 사용하여 지정된 블록의 모든 출력을 캡처합니다.사용 예:
captured_content = capture_stdout do
system 'echo foo'
end
puts captured_content
▁the를 대체할 수 .system내부적으로 호출하는 모든 것으로 호출system유사한 방법을 사용하여 데이터를 캡처할 수도 있습니다.stderr당신이 원한다면요.
을 사용하여 Kernel#system다음과 같은 설명자를 수정할 수 있습니다.
stdout 및 stderr을 추가 모드의 파일(/tmp/log)로 리디렉션:
system('ls -al', :out => ['/tmp/log', 'a'], :err => ['/tmp/log', 'a'])
장시간 실행 명령의 경우 출력이 실시간으로 저장됩니다.IO.파이프를 사용하여 출력을 저장하고 커널 #시스템에서 리디렉션할 수도 있습니다.
직접적인 시스템(...) 대체품으로 Open3.popen3(...)를 사용할 수 있습니다.
추가 논의: http://tech.natemurray.com/2007/03/ruby-shell-commands.html
표준 출력을 val이라는 이름의 변수로 캡처하는 가장 간단한 솔루션:
val = capture(:stdout) do
system("pwd")
end
puts val
단축 버전:
val = capture(:stdout) { system("ls") }
캡처 방법은 active_support/core_ext/context/capture.method를 통해 제공됩니다.
마찬가지로 표준 오류도 캡처할 수 있습니다.:stderr
여기에 이것을 찾지 못해서 추가했는데, 전체 출력을 얻는 데 약간의 문제가 있었습니다.
백틱을 사용하여 STDERR을 캡처하려는 경우 STDOUT로 STDERR을 리디렉션할 수 있습니다.
출력 = 'grep hosts /private/etc/* 2>&1'
출처: http://blog.bigbinary.com/2012/10/18/backtick-system-exec-in-ruby.html
프론트킥이라는 보석을 사용할 수 있습니다.
Frontkick.exec("echo *")
확인하고 읽는 방법은 다음과 같습니다.
result = Frontkick.exec("echo *")
puts result.successful? #=> true if exit_code is 0
puts result.success? #=> alias to successful?, for compatibility with Process::Status
puts result.stdout #=> stdout output of the command
puts result.stderr #=> stderr output of the command
puts result.exit_code #=> exit_code of the command
puts result.status #=> alias to exit_code
puts result.exitstatus #=> alias to exit_code, for compatibility with Process::Status
puts result.duration #=> the time used to execute the command
Github https://github.com/sonots/frontkick#frontkick
젬 페이지 https://rubygems.org/gems/frontkick
가장 편리한 방법은 다음과 같습니다.
stdout_str, stderr_str, status = Open3.capture3(cmd)
puts "exit status: #{status.exitstatus} stdout: #{stdout_str}"
puts `date`
puts $?
Mon Mar 7 19:01:15 PST 2016
pid 13093 exit 0
언급URL : https://stackoverflow.com/questions/690151/getting-output-of-system-calls-in-ruby
'programing' 카테고리의 다른 글
| 메모리에 이미지를 로드하지 않고 이미지 크기 가져오기 (0) | 2023.07.17 |
|---|---|
| Visual Studio의 'Web Site'와 'Project'의 차이점 (0) | 2023.07.17 |
| 오라클 데이터베이스가 자동 커밋으로 설정되어 있는지 확인하려면 어떻게 해야 합니까? (0) | 2023.07.17 |
| Python Git Module 경험이 있습니까? (0) | 2023.07.17 |
| 파이썬으로 URL을 요청하고 리디렉션을 따르지 않는 쉬운 방법이 있습니까? (0) | 2023.07.17 |