User Tools

Site Tools


tips:clojure:exec-shell-command

쉘 명령 실행하기

쉘 명령을 실행하기 위해서는 다음과 같이 하면 된다.

(use '[clojure.java.shell :only [sh]])
>> nil
 
(sh "ls" "-aul")
>> {:exit 0,
 :out "total 64
drwxr-xr-x  11 zkim  staff    374 Jul  5 13:21 .
drwxr-xr-x  25 zkim  staff    850 Jul  5 13:02 ..
drwxr-xr-x  12 zkim  staff    408 Jul  5 13:02 .git
-rw-r--r--   1 zkim  staff     13 Jul  5 13:02 .gitignore
-rw-r--r--   1 zkim  staff  12638 Jul  5 13:02 LICENSE.html
-rw-r--r--   1 zkim  staff   4092 Jul  5 13:02 README.md
drwxr-xr-x   2 zkim  staff     68 Jul  5 13:15 classes
drwxr-xr-x   5 zkim  staff    170 Jul  5 13:15 lib
-rw-r--r--@  1 zkim  staff   3396 Jul  5 13:03 pom.xml
-rw-r--r--@  1 zkim  staff    367 Jul  5 13:15 project.clj
drwxr-xr-x   4 zkim  staff    136 Jul  5 13:15 src
", :err ""}

clojure.java.shell/sh의 소스코드 코드를 보면 실제로는java.lang.Runtime의 exec 메소드중 exec(String[] cmdarray, String[] envp, File dir) 를 사용하는데 다음과 같다.

(.exec (Runtime/getRuntime) 
               ^"[Ljava.lang.String;" (into-array cmd)
               (as-env-strings (:env opts))
               (as-file (:dir opts)))

Runtime.exec의 첫 인자는 (into-array cmd)의 결과로 스트링 배열이 된다. 그래서 위 코드에서 커맨드를 토큰별로 스트링으로 나열하여 sh 함수에 전달한 것이다. 하지만 이런 식으로 파이프를 사용할 수가 없다.

(sh "ls" "-l" "|" "wc" "-l")
>>{:exit 2, :out "", :err "ls: |에 접근할 수 없습니다: 그런 파일이나 디렉터리가 없습니다\nls: wc에 접근할 수 없습니다: 그런 파일이나 디렉터리가 없습니다\n"}

파이프는 커맨드 쉘의 일부이기 때문이기 때문에 다음과 같이 해주어야 한다.

(sh "/bin/sh" "-c" "ls -l | wc -c")
>> {:exit 0, :out "1227\n", :err ""}

다음과 같이 하면 출력문만 얻을 수 있다.

(print (:out (sh "/bin/sh" "-c" "ls -l | wc -c" :dir "/home/psk810/clojure/")))
=> 1378
>> nil

다음과 같이 유틸리티 함수를 만들어 사용하면 편하다.

(defn mysh [& cmd] 
  (:out (apply 
          (partial clojure.java.shell/sh "/bin/sh" "-c") 
          cmd)))
>> #'user/mysh
 
(def out (mysh "find -name \"*.clj\" | xargs wc -l" 
      :dir "/home/psk810/clojure/nREPL"))
>> #'user/s
 
(print out)      
>> 215 ./clojure/tools/nrepl/middleware/session.clj
  213 ./clojure/tools/nrepl/middleware/interruptible_eval.clj
   90 ./clojure/tools/nrepl/middleware/load_file.clj
   29 ./clojure/tools/nrepl/middleware/pr_values.clj
  415 ./clojure/tools/nrepl/bencode.clj
  233 ./clojure/tools/nrepl/t.clj
   49 ./clojure/tools/nrepl/helpers.clj
  163 ./clojure/tools/nrepl/middleware.clj
  140 ./clojure/tools/nrepl/server.clj
   88 ./clojure/tools/nrepl/cmdline.clj
  168 ./clojure/tools/nrepl/transport.clj
   54 ./clojure/tools/nrepl/misc.clj
   52 ./clojure/tools/nrepl/ack.clj
  246 ./clojure/tools/nrepl.clj
 2155 합계
nil
 
(def lines (clojure.string/split out #"\n"))
(pprint lines)
 
(def words (map #(re-seq #"\w+" %) lines))
(print words)
 
(def numbers (map #(re-find #"\d+" %) lines))
(print numbers)
tips/clojure/exec-shell-command.txt · Last modified: 2019/02/04 14:26 (external edit)