简体   繁体   中英

How to use command line arguments in Clojure?

I'm working my way through one of my first Clojure programs. The one thing I have left to do is have my program accept command line arguments. The number of args can vary (but needs to be at least one), and then each command line arg needs to be provided as an argument to a function in my main , one at a time. I've been reading online and it seems that clojure/tools.cli is the way to do it, (using parse-opts maybe?). But I can't figure it out for the life of me. There's no validation, really that needs to happen -- whatever the user would provide would be valid. (The only thing that needs to be checked is that there is at least one argument provided). Any suggestions on how to go about this?

All the examples I run into seem very complicated and go over my head very easily.

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.

I use leiningen to run my programs.

The easy way is to use clojure.core/*command-line-args* :

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

Since your entire question seems to boil down to:

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.

I'll answer that. That can be done fairly succinctly:

(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!"))))

Note, unless you absolutely want to fail outright when 0 arguments are passed, you can skip the seq check. doseq won't run if args is empty since there isn't anything to iterate over.

You can also replace the whole doseq with:

(mapv println args)

But that's arguably an abuse of mapv .

Clojure Spec can do many things, and parsing and validating command line arguments is one of those things. Here is an example:

(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 ships from version 1.9 of Clojure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM