Exec
irb에서 커널의 exec로 명령을 수행하는 방법이 방법은 irb가 exec를 통해서 echo프로세스를 전달받아서 수행됨을 알 수 있다.간단하지만결과가성공됐는지아닌지를판별할방법이없다.
$ irb
>> exec 'echo "hello $HOSTNAME"'
hello nate.local
$
System
시스템(system) 명령을 사용하는 것인데 exec와의 차이는 프로세스가 그대로 전달되지 않고 subshell을 통해 수행된다는 점이다. 그래서 결과를 얻을 수 있는데 성공일 경우 true, 아닐때는 false를 반환한다위에서 system이 전역변수인 $%를 프로세스의 exit상태 값으로 set함을 확인할 수 있다. false 명령의 exit 상태를 확인할 수 있는데(항상 non-zero 값이다) 이렇게 exit값을 확인하므로서 예외 처리가 가능할 수 있겠다.
$ irb
>> system 'echo "hello $HOSTNAME"'
hello nate.local
=> true
>> system 'false'
=> false
>> puts $?
256
=> nil
>>
system은 단지 명령의 성공여부를 알고 싶을 때는 최상이라 말할 수 있겠지만, 어떨때는 표준 출력 내용도 확인할 필요가 있을 텐데 그때는 위의 2 방법은 아니겠다.
Backticks (`)
Backticks (또는 “backquotes”)은 명령을 subshell에서 수행하고 표준 출력을 반환받아 출력한다.이 방법은 유닉스에도 가장 많이 쓰이는 방법인데 명령을 subshell에서 수행하여 얻는 출력을 일반 string으로 재사용하기 쉽게할 수 있다. $%을 보면 단순히 상태 값을 반환하는 것은 아니나 실제로 Process::Status 객체임을 알 수 있다. 단순히 exit 상태 값만이 아니라 프로세스 id도 얻을 수 있는 것이다. Process::Status#to_i 는 integer값으로 exit 상태 값을 반환하고, #to_s는 exit상태를 string으로 반환한다. backticks를 사용하면 얻게되는 결과는 단순히 stdout(표준 출력)만이지 stderr는 얻을 수 없다는 것이다. 아래는 perl을 이용하여 string을 stderr로 출력하는 예이다.
$ irb
>> today = `date`
=> "Mon Mar 12 18:15:35 PDT 2007n"
>> $?
=> #<Process::Status: pid=25827,exited(0)>
>> $?.to_i
=> 0
여기서 변수 warning이 set되지 않은 것을 알 수 있는데. 이것은 위에서 perl의 예에서처럼 backticks으로 얻지 못한 stderr 이다.
$ irb
>> warning = `perl -e "warn 'dust in the wind'"`
dust in the wind at -e line 1.
=> ""
>> puts warning
=> nil
IO#popen
IO#popen 은 subprocess로 명령을 수행할 수 있는 또 하나의 방법이라 할 수 있겠다. popen은 조금의 추가적인 명령을 더 줄수 있는데 subprocess의 stdin과 stdout가 IO객체와 서로 연결가능하다는 것이다.IO#popen 가 괜찮긴 하지만 아래에 소개할 Open3#popen3이 더욱 세밀한 제어가 가능할 듯 하다.
$ irb
>> IO.popen("date") { |f| puts f.gets }
Mon Mar 12 18:58:56 PDT 2007
=> nil
Open3#popen3
루비 표준 라이브러리에 포함된 Open3 클래스는 사용이 아주 간단하고 stdin, stdout 과 stderr을 다 반환한다. 아래의 예에서는 질의식(Interactive) 명령인 dc를 이용한다. dc는 RPN(Reverse Polish Notation) 계산기로 stdin으로 입력을 받는다. 2개의 숫자와 연산자를 스택에 push하고 p 명령을 이용하여 결과를 얻는 예이다.여기서 우리는 출력을 읽을 수 있는 것만이 아닌 입력을 쓸 수 있음을 알 수 있다. 이렇게 Open3 객체로 유연성 높은 쉘 명령 사용이 가능하겠다. popen3로 stderr도 확인이 가능한데...
$ irb
>> stdin, stdout, stderr = Open3.popen3('dc')
=> [#<IO:0x6e5474>, #<IO:0x6e5438>, #<IO:0x6e53d4>]
>> stdin.puts(5)
=> nil
>> stdin.puts(10)
=> nil
>> stdin.puts("+")
=> nil
>> stdin.puts("p")
=> nil
>> stdout.gets
=> "15n"
다만 1.8.5버젼의 루비에서는 exit 상태 값이 $?로 제대로 반환되지 않는 문제가 있다.
# (irb continued...)
>> stdin.puts("asdfasdfasdfasdf")
=> nil
>> stderr.gets
=> "dc: stack emptyn"
0? false는 반드시 non-zero인 exit 상태값을 반환해야한다! 이 결점이 우리를 Open4 객체로 안내한다고 볼 수 있겠다.
$ irb
>> require "open3"
=> true
>> stdin, stdout, stderr = Open3.popen3('false')
=> [#<IO:0x6f39c0>, #<IO:0x6f3984>, #<IO:0x6f3920>]
>> $?
=> #<Process::Status: pid=26285,exited(0)>
>> $?.to_i
=> 0
Open4#popen4
Open4#popen4 은 루비 젬에서 Ara Howard에 의해 추가됐다. Open3와 동작이 같은데, 단지 exit 상태 값을 반환 받을 수 있다는게 다르다. popen4는 subshell의 프로세스 id를 반환하고 exit 상태 값을 waiting 상태에서 받을 수 있다. (gem install open4 로 설치가 가능)Open4의 좋은 점은 popen4를 하나의 block으로 호출할 수 있고 자동으로 반환 상태를 기다리는 대기가 가능하다는 점이다.
$ irb
>> require "open4"
=> true
>> pid, stdin, stdout, stderr = Open4::popen4 "false"
=> [26327, #<IO:0x6dff24>, #<IO:0x6dfee8>, #<IO:0x6dfe84>]
>> $?
=> nil
>> pid
=> 26327
>> ignored, status = Process::waitpid2 pid
=> [26327, #<Process::Status: pid=26327,exited(1)>]
>> status.to_i
=> 256
이상으로 6가지의 쉘 명령 방법을 정리하였는데 명령어의 이름에서도 볼 수 있듯이 일반적인 unix의 명령과 c의 함수와 이름이 유사하여 사용하거나 기억하기 편한 장점과 루비 특유의 순수 객체지향 언어 다움의 간결함으로 앞으로 쉘 스크립트 명령을 사용하는데에 루비의 사용이 많이 증가할 듯 하다는 생각이 든다. 출처 : http://pasadenarb.com/2007/03/ruby-shell-commands.html
$ irb
>> require "open4"
=> true
>> status = Open4::popen4("false") do |pid, stdin, stdout, stderr|
?> puts "PID #{pid}"
>> end
PID 26598
=> #<Process::Status: pid=26598,exited(1)>
>> puts status
256
=> nil
댓글 없음:
댓글 쓰기