Lovetoken

저는 개발 취향을 가진 데이터 분석가 Jr. 입니다.

Navigation
 » Home
 » About Me
 » Github

R에서 Shell command 를 실행하기 위한 대안 : system() 함수

08 Feb 2016 » R



(본 글은 Linux, Mac OS 머신을 기준으로 작성한 글이다)

Shell command 로 출력되는 것을 R에서 보기 위한 방법은 없을까?
예를 들어 워킹디렉토리의 파일리스트를 출력하기 위해선 쉘에다서 간단히 ls, 아니면 ls -al 등으로 참조할 수 있지만 Rstudio 를 사용하고 있는 상황이 아니고선 R command 상황에서 파일리스트를 참조하기는 좀 그렇다.

굳이 찾아본다면 Shell 의 ls -al 와 같은 R코드는

file.info(list.files(all.files = T))
##                   size isdir mode               mtime               ctime
## .                  204  TRUE  755 2017-05-04 14:28:32 2017-05-04 14:28:32
## ..                1394  TRUE  755 2017-05-04 13:54:18 2017-05-04 13:54:18
## .DS_Store         6148 FALSE  644 2017-05-04 14:28:32 2017-05-04 14:28:32
## Rmarkdown.Rmd     4451 FALSE  755 2017-05-04 14:12:34 2017-05-04 14:12:34
## Rmarkdown.html 1037047 FALSE  666 2017-05-04 14:12:41 2017-05-04 14:12:41
## Rmarkdown.md      7150 FALSE  666 2017-05-04 14:12:41 2017-05-04 14:12:41
##                              atime uid gid     uname grname
## .              2017-05-04 14:30:01 501  20 lovetoken  staff
## ..             2017-05-04 13:56:14 501  20 lovetoken  staff
## .DS_Store      2017-05-04 14:11:18 501  20 lovetoken  staff
## Rmarkdown.Rmd  2017-05-04 14:30:01 501  20 lovetoken  staff
## Rmarkdown.html 2017-05-04 14:28:33 501  20 lovetoken  staff
## Rmarkdown.md   2017-05-04 14:13:27 501  20 lovetoken  staff

등을 예시로 들 수 있는데 딱 봐도 마음에 들지 않는다 😨

불필요하게 길은 코드인 것 뿐만아니라
Shell 의 ls 만의 기능을 R의 list.files() 함수가 가지고 있지 못하다.

이처럼 R에서 대체할 수 있는 함수나 코드를 찾기보단 아예 R내에서 Shell command를 실행할 수 있는 방법이 없을까 고민해 보았다.
이것저것 찾아보았는데 system() 함수를 이용하는 방법이 있어 정리해 본다.



R에서 Shell command 입력해 표준출력 조회하기

system("ls -al")
system("pwd")
system("echo Hello world!")

사용방법은 system() 함수의 첫번째 인자인 expression 을 Shell command 로 채워 넣어주면 된다.
아쉽지만 문자열만을 받아들이기 때문에 “” 로 양 옆을 채워야 한다.
현재 글에선 출력결과를 생략하였지만 실제로 R에서 실행 시 원하는 표준출력(stdout)을 볼 수 있다.

Shell 출력물을 R에서 바로 이용하기 위한 intern = TRUE

위의 예제에서 본 출력물을 R 내에서 character 형으로 바로 사용하기 위해선 R의 컨테이너에 저장되어야 한다.
하지만 system() 함수를 이용한 기본출력은 벡터형으로 반환되지 않는다.
출력은 출력일 뿐인 이것을 벡터형으로 반환시키기 위해선 intern = TRUE 로 설정하면 된다.

system("ls -al", intern = T)
## [1] "total 2080"                                                          
## [2] "drwxr-xr-x@  6 lovetoken  staff      204 May  4 14:28 ."             
## [3] "drwxr-xr-x@ 41 lovetoken  staff     1394 May  4 13:54 .."            
## [4] "-rw-r--r--@  1 lovetoken  staff     6148 May  4 14:28 .DS_Store"     
## [5] "-rwxr-xr-x@  1 lovetoken  staff     4451 May  4 14:12 Rmarkdown.Rmd" 
## [6] "-rw-rw-rw-@  1 lovetoken  staff  1037047 May  4 14:12 Rmarkdown.html"
## [7] "-rw-rw-rw-@  1 lovetoken  staff     7150 May  4 14:12 Rmarkdown.md"
system("pwd", intern = T)
## [1] "/Users/lovetoken/Desktop/Dropbox/02_Study/01_Statistic/31_R/11_R_posting/01_function/system"
system("echo Hello world!", intern = T)
## [1] "Hello world!"



Shell 표준출력을 R과 함께 이용

이점을 이용하여 R과 Shell 의 캐미를 만들 수 있을 것이다.

ex1) R 에서의 ‘Hello’ 와 Shell 에서의 ‘R!’ 을 붙여 ‘Hello R!’ 완성시키기

R <- "Hello "
Shell <- system("echo R!", intern = T)

paste0(R, Shell)
## [1] "Hello R!"

ex2) R에서 생성한 규칙적 문자열 데이터들로 폴더 생성하기

R에서 준비된 날짜명칭들을 이용해 Shell mkdir 명령어와 혼합하여 폴더들을 생성해보는 예제이다.

우선 현 워킹디렉토리의 상황을 조회해보면

system("ls -al", intern = T)
## [1] "total 2080"                                                          
## [2] "drwxr-xr-x@  6 lovetoken  staff      204 May  4 14:28 ."             
## [3] "drwxr-xr-x@ 41 lovetoken  staff     1394 May  4 13:54 .."            
## [4] "-rw-r--r--@  1 lovetoken  staff     6148 May  4 14:28 .DS_Store"     
## [5] "-rwxr-xr-x@  1 lovetoken  staff     4451 May  4 14:12 Rmarkdown.Rmd" 
## [6] "-rw-rw-rw-@  1 lovetoken  staff  1037047 May  4 14:12 Rmarkdown.html"
## [7] "-rw-rw-rw-@  1 lovetoken  staff     7150 May  4 14:12 Rmarkdown.md"

폴더따윈 없다.

최근 3일치 날짜명칭들을 R을 통해 만들고
Shell 에서 폴더를 만드는 명령어인 mkdir 과 결합하여
최종적으로 "mkdir 2017-05-02 2017-05-03 2017-05-04" 명령어를 만들어 실행시키는 코드이다.

date <- seq(Sys.Date() - 2, Sys.Date(), by = 1) %>% paste(collapse = " ")
paste("mkdir", date) %>% system(intern = T)
## character(0)

실행 이후 최근 3일치 명칭 폴더 3개가 잘 만들어 졌는지 확인해 보면

system("ls -al", intern = T)
##  [1] "total 2080"                                                          
##  [2] "drwxr-xr-x@  9 lovetoken  staff      306 May  4 14:30 ."             
##  [3] "drwxr-xr-x@ 41 lovetoken  staff     1394 May  4 13:54 .."            
##  [4] "-rw-r--r--@  1 lovetoken  staff     6148 May  4 14:28 .DS_Store"     
##  [5] "drwxr-xr-x   2 lovetoken  staff       68 May  4 14:30 2017-05-02"    
##  [6] "drwxr-xr-x   2 lovetoken  staff       68 May  4 14:30 2017-05-03"    
##  [7] "drwxr-xr-x   2 lovetoken  staff       68 May  4 14:30 2017-05-04"    
##  [8] "-rwxr-xr-x@  1 lovetoken  staff     4451 May  4 14:12 Rmarkdown.Rmd" 
##  [9] "-rw-rw-rw-@  1 lovetoken  staff  1037047 May  4 14:12 Rmarkdown.html"
## [10] "-rw-rw-rw-@  1 lovetoken  staff     7150 May  4 14:12 Rmarkdown.md"

잘 만들어 진 것을 볼 수 있다.



정리

필자는 Shell 에 대해 완전 초급자여서 즐겨 쓰는 명령어 몇 개 이외에 잘 아는것이 없다.
따라서 예제도 저 정도의 수준의 예제 외에 생각나는 아이디어가 바닥이 나버렸다. 😓
하지만 Shell 고수분들은 응용력과 잠재력이 대단할 것인데 R과의 연동된 좋은 아이디어들을 구현할 수 있을 것 같아 감히 system() 함수를 소개한다.