代码之家  ›  专栏  ›  技术社区  ›  Eugene Yokota

解析命令行参数的最佳方法?[关闭]

  •  222
  • Eugene Yokota  · 技术社区  · 15 年前

    在scala中解析命令行参数的最佳方法是什么? 我个人更喜欢不需要外部罐子的轻便的东西。

    相关:

    26 回复  |  直到 6 年前
        1
  •  211
  •   Roberto Bonvallet    10 年前

    object MmlAlnApp {
      val usage = """
        Usage: mmlaln [--min-size num] [--max-size num] filename
      """
      def main(args: Array[String]) {
        if (args.length == 0) println(usage)
        val arglist = args.toList
        type OptionMap = Map[Symbol, Any]
    
        def nextOption(map : OptionMap, list: List[String]) : OptionMap = {
          def isSwitch(s : String) = (s(0) == '-')
          list match {
            case Nil => map
            case "--max-size" :: value :: tail =>
                                   nextOption(map ++ Map('maxsize -> value.toInt), tail)
            case "--min-size" :: value :: tail =>
                                   nextOption(map ++ Map('minsize -> value.toInt), tail)
            case string :: opt2 :: tail if isSwitch(opt2) => 
                                   nextOption(map ++ Map('infile -> string), list.tail)
            case string :: Nil =>  nextOption(map ++ Map('infile -> string), list.tail)
            case option :: tail => println("Unknown option "+option) 
                                   exit(1) 
          }
        }
        val options = nextOption(Map(),arglist)
        println(options)
      }
    }
    

    Map('infile -> test/data/paml-aln1.phy, 'maxsize -> 4, 'minsize -> 2)
    

        2
  •  188
  •   Cameron MacFarland    8 年前

    scopt/scopt

    val parser = new scopt.OptionParser[Config]("scopt") {
      head("scopt", "3.x")
    
      opt[Int]('f', "foo") action { (x, c) =>
        c.copy(foo = x) } text("foo is an integer property")
    
      opt[File]('o', "out") required() valueName("<file>") action { (x, c) =>
        c.copy(out = x) } text("out is a required file property")
    
      opt[(String, Int)]("max") action { case ((k, v), c) =>
        c.copy(libName = k, maxCount = v) } validate { x =>
        if (x._2 > 0) success
        else failure("Value <max> must be >0") 
      } keyValueName("<libname>", "<max>") text("maximum count for <libname>")
    
      opt[Unit]("verbose") action { (_, c) =>
        c.copy(verbose = true) } text("verbose is a flag")
    
      note("some notes.\n")
    
      help("help") text("prints this usage text")
    
      arg[File]("<file>...") unbounded() optional() action { (x, c) =>
        c.copy(files = c.files :+ x) } text("optional unbounded args")
    
      cmd("update") action { (_, c) =>
        c.copy(mode = "update") } text("update is a command.") children(
        opt[Unit]("not-keepalive") abbr("nk") action { (_, c) =>
          c.copy(keepalive = false) } text("disable keepalive"),
        opt[Boolean]("xyz") action { (x, c) =>
          c.copy(xyz = x) } text("xyz is a boolean property")
      )
    }
    // parser.parse returns Option[C]
    parser.parse(args, Config()) map { config =>
      // do stuff
    } getOrElse {
      // arguments are bad, usage message will have been displayed
    }
    

    scopt 3.x
    Usage: scopt [update] [options] [<file>...]
    
      -f <value> | --foo <value>
            foo is an integer property
      -o <file> | --out <file>
            out is a required file property
      --max:<libname>=<max>
            maximum count for <libname>
      --verbose
            verbose is a flag
    some notes.
    
      --help
            prints this usage text
      <file>...
            optional unbounded args
    
    Command: update
    update is a command.
    
      -nk | --not-keepalive
            disable keepalive    
      --xyz <value>
            xyz is a boolean property
    

        3
  •  49
  •   rintcius    12 年前

    Scallop

    import org.rogach.scallop._;
    
    object Conf extends ScallopConf(List("-c","3","-E","fruit=apple","7.2")) {
      // all options that are applicable to builder (like description, default, etc) 
      // are applicable here as well
      val count:ScallopOption[Int] = opt[Int]("count", descr = "count the trees", required = true)
                    .map(1+) // also here work all standard Option methods -
                             // evaluation is deferred to after option construction
      val properties = props[String]('E')
      // types (:ScallopOption[Double]) can be omitted, here just for clarity
      val size:ScallopOption[Double] = trailArg[Double](required = false)
    }
    
    
    // that's it. Completely type-safe and convenient.
    Conf.count() should equal (4)
    Conf.properties("fruit") should equal (Some("apple"))
    Conf.size.get should equal (Some(7.2))
    // passing into other functions
    def someInternalFunc(conf:Conf.type) {
      conf.count() should equal (4)
    }
    someInternalFunc(Conf)
    
        4
  •  27
  •   joslinm    7 年前
    var name = ""
    var port = 0
    var ip = ""
    args.sliding(2, 2).toList.collect {
      case Array("--ip", argIP: String) => ip = argIP
      case Array("--port", argPort: String) => port = argPort.toInt
      case Array("--name", argName: String) => name = argName
    }
    
        5
  •  14
  •   Bruno Bieth    9 年前

    https://github.com/backuity/clist

    scopt

    class Cat extends Command(description = "concatenate files and print on the standard output") {
    
      // type-safety: members are typed! so showAll is a Boolean
      var showAll        = opt[Boolean](abbrev = "A", description = "equivalent to -vET")
      var numberNonblank = opt[Boolean](abbrev = "b", description = "number nonempty output lines, overrides -n")
    
      // files is a Seq[File]
      var files          = args[Seq[File]](description = "files to concat")
    }
    

    Cli.parse(args).withCommand(new Cat) { case cat =>
        println(cat.files)
    }
    

    clist

        6
  •  13
  •   Community CDub    7 年前

    my answer to the Java question of the same topic

    Scala-friendly Java library for command-line parsing that yields clean code

    Person.scala

    import uk.co.flamingpenguin.jewel.cli.Option
    
    trait Person {
      @Option def name: String
      @Option def times: Int
    }
    

    Hello.scala

    import uk.co.flamingpenguin.jewel.cli.CliFactory.parseArguments
    import uk.co.flamingpenguin.jewel.cli.ArgumentValidationException
    
    object Hello {
      def main(args: Array[String]) {
        try {
          val person = parseArguments(classOf[Person], args:_*)
          for (i <- 1 to (person times))
            println("Hello " + (person name))
        } catch {
          case e: ArgumentValidationException => println(e getMessage)
        }
      }
    }
    

    JewelCLI 0.6 JAR

    scalac -cp jewelcli-0.6.jar:. Person.scala Hello.scala
    scala -cp jewelcli-0.6.jar:. Hello --name="John Doe" --times=3
    

    scalac -cp jewelcli-0.6.jar;. Person.scala Hello.scala
    scala -cp jewelcli-0.6.jar;. Hello --name="John Doe" --times=3
    

    Hello John Doe
    Hello John Doe
    Hello John Doe
    
        8
  •  9
  •   Thamme Gowda    8 年前

    args4j

    import org.kohsuke.args4j.{CmdLineException, CmdLineParser, Option}
    
    object CliArgs {
    
      @Option(name = "-list", required = true,
        usage = "List of Nutch Segment(s) Part(s)")
      var pathsList: String = null
    
      @Option(name = "-workdir", required = true,
        usage = "Work directory.")
      var workDir: String = null
    
      @Option(name = "-master",
        usage = "Spark master url")
      var masterUrl: String = "local[2]"
    
    }
    

    //var args = "-listt in.txt -workdir out-2".split(" ")
    val parser = new CmdLineParser(CliArgs)
    try {
      parser.parseArgument(args.toList.asJava)
    } catch {
      case e: CmdLineException =>
        print(s"Error:${e.getMessage}\n Usage:\n")
        parser.printUsage(System.out)
        System.exit(1)
    }
    println("workDir  :" + CliArgs.workDir)
    println("listFile :" + CliArgs.pathsList)
    println("master   :" + CliArgs.masterUrl)
    

    Error:Option "-list" is required
     Usage:
     -list VAL    : List of Nutch Segment(s) Part(s)
     -master VAL  : Spark master url (default: local[2])
     -workdir VAL : Work directory.
    
        9
  •  8
  •   Cedric Beust    13 年前

    JCommander

    object Main {
      object Args {
        @Parameter(
          names = Array("-f", "--file"),
          description = "File to load. Can be specified multiple times.")
        var file: java.util.List[String] = null
      }
    
      def main(args: Array[String]): Unit = {
        new JCommander(Args, args.toArray: _*)
        for (filename <- Args.file) {
          val f = new File(filename)
          printf("file: %s\n", f.getName)
        }
      }
    }
    
        10
  •  8
  •   Remko Popma    7 年前

    • <command> -xvfInputFile <command> -x -v -f InputFile
    • "1..*" "3..5"

    Extended usage help message source

    picocli demo

        11
  •  5
  •   haggy    8 年前

    case class AppArgs(
                  seed1: String,
                  seed2: String,
                  ip: String,
                  port: Int
                  )
    object AppArgs {
      def empty = new AppArgs("", "", "", 0)
    }
    
    val args = Array[String](
      "--seed1", "akka.tcp://seed1",
      "--seed2", "akka.tcp://seed2",
      "--nodeip", "192.167.1.1",
      "--nodeport", "2551"
    )
    
    val argsInstance = args.sliding(2, 1).toList.foldLeft(AppArgs.empty) { case (accumArgs, currArgs) => currArgs match {
        case Array("--seed1", seed1) => accumArgs.copy(seed1 = seed1)
        case Array("--seed2", seed2) => accumArgs.copy(seed2 = seed2)
        case Array("--nodeip", ip) => accumArgs.copy(ip = ip)
        case Array("--nodeport", port) => accumArgs.copy(port = port.toInt)
        case unknownArg => accumArgs // Do whatever you want for this case
      }
    }
    
        13
  •  3
  •   Byron Ruth    11 年前

    def parseOptions(args: List[String], required: List[Symbol], optional: Map[String, Symbol], options: Map[Symbol, String]): Map[Symbol, String] = {
      args match {
        // Empty list
        case Nil => options
    
        // Keyword arguments
        case key :: value :: tail if optional.get(key) != None =>
          parseOptions(tail, required, optional, options ++ Map(optional(key) -> value))
    
        // Positional arguments
        case value :: tail if required != Nil =>
          parseOptions(tail, required.tail, optional, options ++ Map(required.head -> value))
    
        // Exit if an unknown argument is received
        case _ =>
          printf("unknown argument(s): %s\n", args.mkString(", "))
          sys.exit(1)
      }
    }
    
    def main(sysargs Array[String]) {
      // Required positional arguments by key in options
      val required = List('arg1, 'arg2)
    
      // Optional arguments by flag which map to a key in options
      val optional = Map("--flag1" -> 'flag1, "--flag2" -> 'flag2)
    
      // Default options that are passed in
      var defaultOptions = Map()
    
      // Parse options based on the command line args
      val options = parseOptions(sysargs.toList, required, optional, defaultOptions)
    }
    
        14
  •  3
  •   bjorno    8 年前

    Map[String,String] .contains toInt

    def argsToOptionMap(args:Array[String]):Map[String,String]= {
      def nextOption(
          argList:List[String], 
          map:Map[String, String]
        ) : Map[String, String] = {
        val pattern       = "--(\\w+)".r // Selects Arg from --Arg
        val patternSwitch = "-(\\w+)".r  // Selects Arg from -Arg
        argList match {
          case Nil => map
          case pattern(opt)       :: value  :: tail => nextOption( tail, map ++ Map(opt->value) )
          case patternSwitch(opt) :: tail => nextOption( tail, map ++ Map(opt->null) )
          case string             :: Nil  => map ++ Map(string->null)
          case option             :: tail => {
            println("Unknown option:"+option) 
            sys.exit(1)
          }
        }
      }
      nextOption(args.toList,Map())
    }
    

    val args=Array("--testing1","testing1","-a","-b","--c","d","test2")
    argsToOptionMap( args  )
    

    res0: Map[String,String] = Map(testing1 -> testing1, a -> null, b -> null, c -> d, test2 -> null)
    
        15
  •  2
  •   Anonymous    14 年前
        16
  •  2
  •   sellmerfud    14 年前
        17
  •  2
  •   DavidGamba Darshan Rivka Whittle    10 年前

    Getopt::Long

    def print_version() = () => println("version is 0.2")
    
    def main(args: Array[String]) {
      val (options, remaining) = OptionParser.getOptions(args,
        Map(
          "-f|--flag"       -> 'flag,
          "-s|--string=s"   -> 'string,
          "-i|--int=i"      -> 'int,
          "-f|--float=f"    -> 'double,
          "-p|-procedure=p" -> { () => println("higher order function" }
          "-h=p"            -> { () => print_synopsis() }
          "--help|--man=p"  -> { () => launch_manpage() },
          "--version=p"     -> print_version,
        ))
    

    script

    $ script hello -f --string=mystring -i 7 --float 3.14 --p --version world -- --nothing
    

    higher order function
    version is 0.2
    

    remaining = Array("hello", "world", "--nothing")
    
    options = Map('flag   -> true,
                  'string -> "mystring",
                  'int    -> 7,
                  'double -> 3.14)
    

    scala-getoptions

        18
  •  2
  •   Community CDub    7 年前

    my simple enumeration

    val args: Array[String] = "-silent -samples 100 -silent".split(" +").toArray
                                                  //> args  : Array[String] = Array(-silent, -samples, 100, -silent)
    object Opts extends Enumeration {
    
        class OptVal extends Val {
            override def toString = "-" + super.toString
        }
    
        val nopar, silent = new OptVal() { // boolean options
            def apply(): Boolean = args.contains(toString)
        }
    
        val samples, maxgen = new OptVal() { // integer options
            def apply(default: Int) = { val i = args.indexOf(toString) ;  if (i == -1) default else args(i+1).toInt}
            def apply(): Int = apply(-1)
        }
    }
    
    Opts.nopar()                              //> res0: Boolean = false
    Opts.silent()                             //> res1: Boolean = true
    Opts.samples()                            //> res2: Int = 100
    Opts.maxgen()                             //> res3: Int = -1
    

        19
  •  2
  •   Holger Brandl    9 年前

    http://docopt.org/ https://github.com/docopt/docopt.java

    import org.docopt.Docopt
    
    import scala.collection.JavaConversions._
    import scala.collection.JavaConverters._
    
    val doc =
    """
    Usage: my_program [options] <input>
    
    Options:
     --sorted   fancy sorting
    """.stripMargin.trim
    
    //def args = "--sorted test.dat".split(" ").toList
    var results = new Docopt(doc).
      parse(args()).
      map {case(key, value)=>key ->value.toString}
    
    val inputFile = new File(results("<input>"))
    val sorted = results("--sorted").toBoolean
    
        20
  •  1
  •   Alan Jurgensen    11 年前

    http://www.scala-lang.org/old/node/4380

    object ArgParser {
      val usage = """
    Usage: parser [-v] [-f file] [-s sopt] ...
    Where: -v   Run verbosely
           -f F Set input file to F
           -s S Set Show option to S
    """
    
      var filename: String = ""
      var showme: String = ""
      var debug: Boolean = false
      val unknown = "(^-[^\\s])".r
    
      val pf: PartialFunction[List[String], List[String]] = {
        case "-v" :: tail => debug = true; tail
        case "-f" :: (arg: String) :: tail => filename = arg; tail
        case "-s" :: (arg: String) :: tail => showme = arg; tail
        case unknown(bad) :: tail => die("unknown argument " + bad + "\n" + usage)
      }
    
      def main(args: Array[String]) {
        // if there are required args:
        if (args.length == 0) die()
        val arglist = args.toList
        val remainingopts = parseArgs(arglist,pf)
    
        println("debug=" + debug)
        println("showme=" + showme)
        println("filename=" + filename)
        println("remainingopts=" + remainingopts)
      }
    
      def parseArgs(args: List[String], pf: PartialFunction[List[String], List[String]]): List[String] = args match {
        case Nil => Nil
        case _ => if (pf isDefinedAt args) parseArgs(pf(args),pf) else args.head :: parseArgs(args.tail,pf)
      }
    
      def die(msg: String = usage) = {
        println(msg)
        sys.exit(1)
      }
    
    }
    
        21
  •  1
  •   gwenzek    10 年前

    https://gist.github.com/gwenzek/78355526e476e08bb34d

    import ***.ArgsOps._
    
    
    object Example {
        val parser = ArgsOpsParser("--someInt|-i" -> 4, "--someFlag|-f", "--someWord" -> "hello")
    
        def main(args: Array[String]){
            val argsOps = parser <<| args
            val someInt : Int = argsOps("--someInt")
            val someFlag : Boolean = argsOps("--someFlag")
            val someWord : String = argsOps("--someWord")
            val otherArgs = argsOps.args
    
            foo(someWord, someInt, someFlag)
        }
    }
    

        22
  •  1
  •   J Calbreath    9 年前

    input--hdfs:/path/to/myData/part-00199.avro output--hdfs:/path/toWrite/Data fileFormat--avro option1--5
    

    Array("input--hdfs:/path/to/myData/part-00199.avro", "output--hdfs:/path/toWrite/Data","fileFormat--avro","option1--5")
    

    val nArgs = args.map(x=>x.split("--")).map(y=>(y(0),y(1))).toMap
    

    Map(input -> hdfs:/path/to/myData/part-00199.avro, output -> hdfs:/path/toWrite/Data, fileFormat -> avro, option1 -> 5)
    

        23
  •  1
  •   Valentin Tihomirov    9 年前

        def optArg(prefix: String) = args.drop(3).find { _.startsWith(prefix) }.map{_.replaceFirst(prefix, "")}
        def optSpecified(prefix: String) = optArg(prefix) != None
        def optInt(prefix: String, default: Int) = optArg(prefix).map(_.toInt).getOrElse(default)
    

    -Xmx<size>

    val cacheEnabled = optSpecified("cacheOff")
    val memSize = optInt("-Xmx", 1000)
    

        24
  •  1
  •   auselen    9 年前

    val args = "--sw1 1 input_1 --sw2 --sw3 2 input_2 --sw4".split(" ")
    val (options, inputs) = OptParser.parse(args)
    

    options: Map[Symbol,Any] = Map('sw1 -> 1, 'sw2 -> true, 'sw3 -> 2, 'sw4 -> true)
    inputs: List[Symbol] = List('input_1, 'input_2)
    

    object OptParser {
      val map: Map[Symbol, Any] = Map()
      val list: List[Symbol] = List()
    
      def parse(args: Array[String]): (Map[Symbol, Any], List[Symbol]) = _parse(map, list, args.toList)
    
      private [this] def _parse(map: Map[Symbol, Any], list: List[Symbol], args: List[String]): (Map[Symbol, Any], List[Symbol]) = {
        args match {
          case Nil => (map, list)
          case arg :: value :: tail if (arg.startsWith("--") && !value.startsWith("--")) => _parse(map ++ Map(Symbol(arg.substring(2)) -> value), list, tail)
          case arg :: tail if (arg.startsWith("--")) => _parse(map ++ Map(Symbol(arg.substring(2)) -> true), list, tail)
          case opt :: tail => _parse(map, list :+ Symbol(opt), tail)
        }
      }
    }
    
        25
  •  1
  •   pavlosgi    7 年前

    freecli

    package freecli
    package examples
    package command
    
    import java.io.File
    
    import freecli.core.all._
    import freecli.config.all._
    import freecli.command.all._
    
    object Git extends App {
    
      case class CommitConfig(all: Boolean, message: String)
      val commitCommand =
        cmd("commit") {
          takesG[CommitConfig] {
            O.help --"help" ::
            flag --"all" -'a' -~ des("Add changes from all known files") ::
            O.string -'m' -~ req -~ des("Commit message")
          } ::
          runs[CommitConfig] { config =>
            if (config.all) {
              println(s"Commited all ${config.message}!")
            } else {
              println(s"Commited ${config.message}!")
            }
          }
        }
    
      val rmCommand =
        cmd("rm") {
          takesG[File] {
            O.help --"help" ::
            file -~ des("File to remove from git")
          } ::
          runs[File] { f =>
            println(s"Removed file ${f.getAbsolutePath} from git")
          }
        }
    
      val remoteCommand =
       cmd("remote") {
         takes(O.help --"help") ::
         cmd("add") {
           takesT {
             O.help --"help" ::
             string -~ des("Remote name") ::
             string -~ des("Remote url")
           } ::
           runs[(String, String)] {
             case (s, u) => println(s"Remote $s $u added")
           }
         } ::
         cmd("rm") {
           takesG[String] {
             O.help --"help" ::
             string -~ des("Remote name")
           } ::
           runs[String] { s =>
             println(s"Remote $s removed")
           }
         }
       }
    
      val git =
        cmd("git", des("Version control system")) {
          takes(help --"help" :: version --"version" -~ value("v1.0")) ::
          commitCommand ::
          rmCommand ::
          remoteCommand
        }
    
      val res = runCommandOrFail(git)(args).run
    }
    

    Usage

        26
  •  0
  •   botkop    8 年前

    def main(args: Array[String]) {
        val cli = args.map(_.split("=") match { case Array(k, v) => k->v } ).toMap
        val saveAs = cli("saveAs")
        println(saveAs)
    }
    
    推荐文章