programing

Ruby에서 시스템() 호출의 출력을 가져오는 중

elecom 2023. 7. 17. 20:40
반응형

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

반응형