如何在 Clojure 中使用命令行参数?

How to use command line arguments in Clojure?

我正在完成我的第一个 Clojure 程序。我剩下要做的一件事是让我的程序接受命令行参数。 args 的数量可以变化(但至少需要一个),然后每个命令行 arg 需要作为参数提供给我的 main 中的函数,一次一个。我一直在网上阅读,似乎 clojure/tools.cli 是做到这一点的方法(也许使用 parse-opts?)。但是我一辈子都弄不明白。没有验证,确实需要进行验证——用户提供的任何内容都是有效的。 (唯一需要检查的是至少提供了一个参数)。关于如何解决这个问题有什么建议吗?

我 运行 中的所有示例看起来都非常复杂,很容易让我难以理解。

我尝试做的一个简单示例是在用户提供任意数量的命令行参数后,让 clojure 在终端的新行中​​打印每个字符串。

我使用 leiningen 运行 我的程序。

最简单的方法是使用 clojure.core/*command-line-args*:

(doseq [arg *command-line-args*]
  (println (str "Read an argument: " arg)))

因为你的整个问题似乎可以归结为:

An easy example of what I'm trying to do is after a user provides any number of command line arguments, then have clojure print each string in a new line of the terminal.

我会回答的。这可以相当简洁地完成:

(defn -main [& args] ; & creates a list of var-args
  (if (seq args)
    ; Foreach arg, print the arg...
    (doseq [arg args]
      (println arg))

    ; Handle failure however here
    (throw (Exception. "Must have at least one argument!"))))

请注意,除非您绝对 想在传递 0 个参数时彻底失败,否则您可以跳过 seq 检查。如果 args 为空,doseq 不会 运行,因为没有任何可迭代的内容。

您也可以将整个 doseq 替换为:

(mapv println args)

但这可以说是对 mapv 的滥用。

Clojure Spec 可以做很多事情,解析和验证命令行参数就是其中之一。这是一个例子:

(ns cmdargs.core
  (:require [clojure.spec.alpha :as spec]))

;; Specification of a single argument.
;; For example, replace `any?` by `number?`
;; if your program only accepts numeric args.
(spec/def ::arg any?)

(spec/def ::args (spec/+ ::arg))

(defn my-fun [& args]
  (doseq [arg args]
    (println "Got arg: " arg)))

(defn -main [& args]
  (let [parsed-args (spec/conform ::args args)]
    (if (= ::spec/invalid parsed-args)
      (do (println "Bad commandline arguments")
          (spec/explain ::args args))
      (apply my-fun parsed-args))))

Clojure Spec 从 Clojure 1.9 版发布。