2010-08-05 39 views
4

我正在嘗試編寫一個庫來執行一些特定於域的內容。我想添加一些腳本到這個庫,可以直接從命令行運行。在腳本中讀取命令行參數問題

目錄佈局:

+- project.clj 
+- src/ 
| +- my-lib.clj 
| +- my-lib/ 
|  +- my-sub-1.clj 
+- scripts/ 
    +- run-command.sh 

在src /我-lib.clj文件加載的我的LIB /我的子1.clj文件:

(ns my-lib 
    (:use [my-lib.my-sub-1]) 
) 

在src /我 - lib/my-sub-1.clj文件包含我想提供的功能。其中一個函數叫做「convert」,它有兩個參數:一個輸入文件名和一個輸出文件名;它轉換文件格式。要使用它:

(convert "input-file.txt" "output-file.txt") 

的(做某事,有趣)和(轉換)功能的src /我-lib中/我的子1.clj是這樣的:

(defn do-something-interesting 
    [input-file output-file] 
    (magic-happens-here input-file output-file)) 

(defn convert 
    [args] 
    (let [infile (first args) 
     outfile (second args)] 
    (do-something-interesting infile outfile))) 

我目前的目標是:在帶有兩個參數的「scripts」目錄中創建腳本「run-command.sh」:輸入文件名和輸出文件名。它應該是可以運行的腳本:

./run-command.sh input-file.txt output-file.txt 

我有run-command.sh工作,只要我硬編碼在腳本文件名使用(做某事,有趣的)功能而不是(轉換)。我一直無法尚未從參數列表讀...

該作品run-command.sh腳本:

#!/bin/sh 
java -cp "../lib/*":"../src":$CLASSPATH clojure.main -e " 
(use '[my-lib my-sub-1]) 
(do-something-interesting "path-to-input-file" "path-to-output-file") 
" 

...但不工作:

#!/bin/sh 
java -cp "../lib/*":"../src":$CLASSPATH clojure.main -e " 
(use '[my-lib my-sub-1]) 
(convert *command-line-args*) 
" 

我得到的錯誤是:

Exception in thread "main" java.lang.IllegalArgumentException: No implementation of method: :reader of protocol: #'clojure.contrib.io/Streams found for class: nil (NO_SOURCE_FILE:0) 
at clojure.lang.Compiler.eval(Compiler.java:5435) 
at clojure.lang.Compiler.eval(Compiler.java:5386) 
at clojure.core$eval.invoke(core.clj:2382) 
at clojure.main$eval_opt.invoke(main.clj:235) 
at clojure.main$initialize.invoke(main.clj:254) 
at clojure.main$null_opt.invoke(main.clj:279) 
at clojure.main$main.doInvoke(main.clj:354) 
at clojure.lang.RestFn.invoke(RestFn.java:422) 
at clojure.lang.Var.invoke(Var.java:369) 
at clojure.lang.AFn.applyToHelper(AFn.java:165) 
at clojure.lang.Var.applyTo(Var.java:482) 
at clojure.main.main(main.java:37) 
Caused by: java.lang.IllegalArgumentException: No implementation of method: :reader of protocol: #'clojure.contrib.io/Streams found for class: nil 
at clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:471) 
at clojure.contrib.io$eval32$fn__33$G__23__38.invoke(io.clj:118) 
at bioclojure.vcf$header.invoke(vcf.clj:22) 
at bioclojure.vcf$column_header.invoke(vcf.clj:55) 
at bioclojure.vcf$column_names.invoke(vcf.clj:61) 
at bioclojure.vcf$vcf2tsv.invoke(vcf.clj:169) 
at bioclojure.vcf$convert.invoke(vcf.clj:185) 
at user$eval474.invoke(NO_SOURCE_FILE:3) 
at clojure.lang.Compiler.eval(Compiler.java:5419) 
... 11 more 

我已經試過「使用」腳本文件中荷蘭國際集團clojure.contrib.io run-command.sh本身,並在頂級庫文件my-lib.clj內,但目前爲止沒有運氣...

如果有人能幫助我,那會很棒。

1月。

回答

3

你應該考慮使用「創一流」的功能來處理在編譯的命令 行參數Clojure/Java功能,而不是通過Clojures main/repl函數即時評估Clojure代碼:

(ns commandline 
    (:gen-class)) 

(defn -main [& args] 
    (convert args)) 

使用雷音罐子創建應用程序的Jar文件,並通過在shell skript 命令行參數的主要功能:

#!/bin/bash 

java -cp "../lib/*":../YOURPROJECT.jar:$CLASSPATH commandline "[email protected]" 
+0

嗨Jurgen, 我試過遠離gen-class,因爲它爲不知道java爲自己的人增加了額外的複雜程度。但是這看起來很簡單:-)會試試看。 – jandot 2010-08-06 13:17:27

+0

如果您已經使用Leiningen編譯/ jar只是另一個任務。 – 2010-08-06 14:07:33

+0

這個工作非常棒。我的-lib.clj文件現在看起來是這樣的: (NS我-lib的 (:使用[我-lib.my-SUB-1]) (:創一流) ) (DEFN - 主[命令與參數] (case命令 「幫助」(的println 「一些幫助信息」) 「轉換」(DO-東西,有用的(第一個參數)(第二參數)))) 然後, 「雷音編譯」 和「lein uberjar」。 這使我可以根據同一個jar文件製作多個命令。我知道我應該重寫-main來處理nils,或者只是使用[&args],但謝謝! – jandot 2010-08-06 17:15:13

1

這是因爲你沒有指定cli參數。您必須致電java .... clojure.main some-script.clj a b c。然後,a,b和c將包含在*command-line-args*中。

0

由於kotarak的建議,我找到了解決方案。在run-command.sh中,我需要使用bash-way而不是clojure方式來引用參數。我甚至不需要單獨的(轉換)功能。

腳本看起來是什麼樣的:

#!/bin/sh 
java -cp "../lib/*":"../src":$CLASSPATH clojure.main -e " 
(use '[my-lib my-sub-1]) 
(convert *command-line-args*) 
" 

它應該是什麼樣子:

#!/bin/sh 
java -cp "../lib/*":"../src":$CLASSPATH clojure.main -e " 
(use '[my-lib my-sub-1]) 
(do-something-interesting \"$1\" \"$2\") 
" 
+1

這仍然沒有完全做到這一點的正確方法。考慮如果'$ 1'是由單個雙引號字符組成的字符串會發生什麼。 kotarak的答案意味着你的腳本應該在'clojure.main'參數後面將'.clj'腳本的名字和所有的命令行參數作爲常規的CLI參數傳遞給'java'命令。然後這些將被傳遞給'clojure.main'類的'main'方法,後者將依次運行命名的腳本,同時安排將後續的CLI參數集合到'* command-line-args *'Var中。 – 2010-08-05 16:41:58