在脚本中发出读取命令行参数的问题

时间:2010-08-05 14:23:55

标签: clojure

我正在尝试编写一个库来执行某些特定于域的操作。我想在这个库中添加一些脚本,可以直接从命令行运行。

目录布局:

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

src / my-lib.clj文件加载my-lib / my-sub-1.clj文件:

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

src / my-lib / my-sub-1.clj文件包含我想要提供的功能。其中一个函数称为“convert”,它有两个参数:输入文件名和输出文件名;它转换文件格式。使用它:

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

src / my-lib / my-sub-1.clj中的(do-something-interesting)和(convert)函数如下所示:

(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工作正常,只要我使用(do-something-interesting)函数而不是(convert)对该脚本中的文件名进行硬编码。我还没有能够从参数列表中读到...

运行的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

我已尝试在脚本文件run-command.sh中使用clojure.contrib.io,并在顶级库文件my-lib.clj中,但到目前为止没有运气......

如果有人能帮助我,那就太好了。

一月

3 个答案:

答案 0 :(得分:3)

您应该考虑使用“gen-class”功能来处理命令 在编译的Clojure / Java函数中的行参数,而不是 通过Clojures main / repl函数即时评估Clojure代码:

(ns commandline
  (:gen-class))

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

使用 lein jar 创建应用程序的Jar文件并传递 shell中的命令行参数会覆盖到main函数:

#!/bin/bash

java -cp "../lib/*":../YOURPROJECT.jar:$CLASSPATH commandline "$@"

答案 1 :(得分:1)

那是因为你没有指定cli参数。你必须致电java .... clojure.main some-script.clj a b c。然后a,b和c将包含在*command-line-args*

答案 2 :(得分: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\")
"