কমান্ড-লাইন পরামিতিগুলি পার্স করার সর্বোত্তম উপায়? [বন্ধ]


237

স্কালায় কমান্ড-লাইন প্যারামিটারগুলি পার্স করার সর্বোত্তম উপায় কী? আমি ব্যক্তিগতভাবে হালকা কিছু পছন্দ করি যার জন্য বাহ্যিক জারের প্রয়োজন হয় না।

সম্পর্কিত:

উত্তর:


228

বেশিরভাগ ক্ষেত্রে আপনার কোনও বহিরাগত পার্সার প্রয়োজন হয় না। স্কালার প্যাটার্নের মিলটি ক্রিয়ামূলক শৈলীতে আরোগ্যগুলি গ্রাস করার অনুমতি দেয়। উদাহরণ স্বরূপ:

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)

এই সংস্করণটি কেবল একটি পীড়িত করে। উন্নত করা সহজ (একটি তালিকা ব্যবহার করে)।

আরও মনে রাখবেন যে এই পদ্ধতির ফলে একাধিক কমান্ড লাইন আর্গুমেন্টের সংমিশ্রণের অনুমতি পাওয়া যায় - এমনকি আরও দুটিও!


4
isSwitch কেবল প্রথম চরিত্রটি ড্যাশ হওয়ার জন্য কেবল তা যাচাই করে '-'
pjotrp

6
nextOptionফাংশনটির জন্য কোনও ভাল নাম নয়। এটি এমন একটি ফাংশন যা কোনও মানচিত্র ফিরিয়ে দেয় - এটি পুনরাবৃত্ত হওয়ার বিষয়টি বাস্তবায়নের বিশদ। এটি maxকোনও সংগ্রহের জন্য একটি ফাংশন লেখার এবং এটিকে কল করার মতো nextMaxকারণ আপনি এটি স্পষ্ট পুনরাবৃত্তি দিয়ে লিখেছিলেন। কেন শুধু এটিকে ডাকবে না optionMap?
ব্রুস

4
@itsbruce আমি আপনার পয়েন্টটি কেবল যুক্ত করতে / সংশোধন করতে চাই - এটি একটি চূড়ান্ত রেখার বক্তব্য সহ, এর মধ্যে সংজ্ঞায়িত listToOptionMap(lst:List[String])ফাংশনটির সাথে সংজ্ঞায়িতযোগ্যতা / রক্ষণাবেক্ষণযোগ্যতা থেকে সবচেয়ে "যথাযথ" হবে । এটি বলেছিল, আমাকে স্বীকার করতে হবে যে আমি আমার উত্তরে এই উত্তরটির চেয়ে অনেক বেশি গুরুতর শর্টকাট তৈরি করেছি। nextOptionreturn nextOption(Map(), lst)
tresbot

6
উপরের কোডটিতে @ ম্যাডকিংয়ের exit(1)প্রয়োজন হতে পারেsys.exit(1)
ট্রেসবট

3
আমি আপনার সমাধান পছন্দ। এখানে পরিবর্তন একাধিক হ্যান্ডেল করতে fileপ্যারামিটার: case string :: tail => { if (isSwitch(string)) { println("Unknown option: " + string) sys.exit(1) } else nextOption(map ++ Map('files -> (string :: map('files).asInstanceOf[List[String]])), tail)। মানচিত্র এছাড়াও ডিফল্ট মান প্রয়োজন Nil, অর্থাত্ val options = nextOption(Map() withDefaultValue Nil, args.toList)। মানগুলি ধরণের হওয়ার asInstanceOfকারণে যা আমি পছন্দ করি না তা অবলম্বন করা । এর চেয়ে ভাল সমাধান কি আছে? OptionMapAny
মাউরো লেসি

196

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

আমি বর্তমানে এটি ব্যবহার করি। খুব বেশি লাগেজ ছাড়াই ব্যবহার পরিষ্কার করুন। (অস্বীকৃতি: আমি এখন এই প্রকল্পটি বজায় রাখছি)


6
আমি বিল্ডার প্যাটার্নটি ডিএসএলকে আরও ভাল পছন্দ করি কারণ এটি মডিউলগুলিতে প্যারামিটার নির্মাণের প্রতিনিধিটিকে সক্ষম করে।
ড্যানিয়েল সি সোব্রাল

3
দ্রষ্টব্য: দেখানো অসদৃশ, Scopt এর জন্য অনেক ধরণের টিকা দরকার নেই।
ব্লেসরব্লেড

9
যদি আপনি এটি একটি স্পার্ক কাজের জন্য আরগগুলি পার্সিংয়ের জন্য ব্যবহার করেন তবে সতর্কতা অবলম্বন করুন যে তারা একসাথে সুন্দরভাবে না খেলে। আক্ষরিক কিছুই আমি scopt সঙ্গে :-( কাজ স্ফুলিঙ্গ জমা দিতে পেতে পারে চেষ্টা
jbrown

4
@ বার্ডজাগুআরআইভিভি স্পার্ক যদি স্কোপট ব্যবহার করে তবে সম্ভবত এটি সমস্যা ছিল - জার বা কোনও কিছুর বিরোধী সংস্করণ। পরিবর্তে আমি স্পার্ক জব দিয়ে স্ক্যাললপ ব্যবহার করি এবং কোনও সমস্যা হয়নি।
jbrown

12
হাস্যকরভাবে যদিও এই লাইব্রেরিটি স্বয়ংক্রিয়ভাবে ভাল সিএলআই ডকুমেন্টেশন উত্পন্ন করেছে, কোডটি ব্রেইনফ * সিকে থেকে কিছুটা ভাল দেখায়।
জোনাথন নিউফিল্ড

58

আমি বুঝতে পারি যে প্রশ্নটি কিছু সময় আগে জিজ্ঞাসা করা হয়েছিল, তবে আমি ভেবেছিলাম এটি সম্ভবত কিছু লোককে, যারা আমার মতো) গুগল করছে এবং এই পৃষ্ঠাটি হিট করছে তাদের সহায়তা করতে পারে।

স্ক্যালপ দেখতে বেশ আশাব্যঞ্জক দেখাচ্ছে।

বৈশিষ্ট্যগুলি (লিঙ্কযুক্ত গিথুব পৃষ্ঠা থেকে উদ্ধৃতি):

  • পতাকা, একক মান এবং একাধিক মান বিকল্প
  • পজিএক্স-স্টাইলে সংক্ষিপ্ত বিকল্পের নাম (-a) গ্রুপিং (-abc) সহ
  • GNU- শৈলীর দীর্ঘ বিকল্পের নাম (--opt)
  • সম্পত্তি যুক্তি (-ডকি = মান, -D কী 1 = মান কী 2 = মান)
  • নন-স্ট্রিং ধরণের বিকল্প এবং বৈশিষ্ট্যগুলির মানগুলি (প্রসারিত রূপান্তরকারী সহ)
  • পিছনে থাকা আরগগুলিতে শক্তিশালী মিল
  • subcommands

এবং কিছু উদাহরণ কোড (সেই গিথুব পৃষ্ঠা থেকেও):

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
স্ক্যাললপ ফিচারগুলির বিশ্রামের অংশগুলি নীচে রাখে। "প্রথম উত্তর জয়" এর স্বাভাবিক এসও ট্রেন্ড
লজ্জাজনকভাবে এটিকে

আমি রাজী. এখানে একটি মন্তব্য রেখে কেবল @ ইউজিন ইওকোটার একটি নোট নিতে মিস করেছেন ase এই ব্লগটি স্ক্যালপ দেখুন
প্রমিত

1
স্কপটির সাথে এটি যে সমস্যাটি বিবেচনা করে তা হ'ল "এটি দুর্দান্ত দেখায় তবে বিকল্পগুলির বিশ্লেষণ করতে অক্ষম, যা আর্গুমেন্টের একটি তালিকা নেয় (যেমন -a 1 2 3) And এবং তালিকাগুলি পাওয়ার জন্য আপনার এটি বাড়ানোর কোনও উপায় নেই (বিন্যাস বাদ দিয়ে) liberal এর সংক্ষিপ্ত রূপ)। " তবে এটি আর সত্য নয়, github.com/scopt/scopt#options দেখুন
আলেক্সি রোমানভ

2
এটি স্কোপ্টের চেয়ে বেশি স্বজ্ঞাত এবং কম বয়লারপ্লেট। আর (x, c) => c.copy(xyz = x) স্কোপে নেই
ওয়েইচিং 清 煒 清

43

আমি তুলনামূলকভাবে সহজ কনফিগারেশনের জন্য যুক্তিগুলির উপর স্লাইডিং পছন্দ করি ।

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
}

2
চালাক। প্রতিটি আর্গ যদি একটি মান নির্দিষ্ট করে তবেই কাজ করে, ঠিক আছে?
ব্রেন্ট ফাউস্ট 1

2
এটা করা উচিত নয় args.sliding(2, 2)?
এম01

1
এটা করা উচিত নয় var port = 0?
সোদেব

17

কমান্ড লাইন ইন্টারফেস স্কালা টুলকিট (CLIST)

এখানেও আমার! (যদিও খেলায় কিছুটা দেরি হয়েছে)

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


এটির বৈধতা আছে কি?
কেএফ

হ্যাঁ এটি করে ( উদাহরণের জন্য github.com/backuity/clist/blob/master/demo/src/main/scala/… দেখুন )। যদিও এটি ডকুমেন্টেড নয় ... পিআর? :)
ব্রুনো বিথ

চেষ্টা করেছেন, বেশ সুবিধাজনক। আমি আগে স্কোপ ব্যবহার করতাম, আমি এখনও একসাথে বৈধতা যুক্ত করতে অভ্যস্ত হই না, তবে কেবল প্রতিটি প্যারামিটারের সংজ্ঞায় নেই। তবে এটি আমার সাথে ভাল কাজ করে। এবং বিভিন্ন বৈশিষ্ট্যে বিভিন্ন প্যারামিটার এবং বৈধতাগুলি সংজ্ঞায়িত করা, তারপরে তাদেরকে বিভিন্ন ক্ষেত্রে একত্রিত করা, এটি আসল সহায়ক। প্যারামিটারগুলি পুনরায় ব্যবহার করা সুবিধাজনক না হলে আমি স্ক্যাপে অনেক ক্ষতি করেছি। উত্তর দেওয়ার জন্য ধন্যবাদ!
কেএফ

সর্বাধিক যাচাই কমান্ড লাইন প্যারামিটার (দেখতে deserialization সময় সঞ্চালিত হয় পড়ুন ,) তাই যদি আপনি ধরনের মাধ্যমে আপনার বৈধতা সীমাবদ্ধতার বর্ণনা করতে পারেন (যেমন Password, Hex, ...), তাহলে আপনি এই লিভারেজ পারবেন না।
ব্রুনো বিথ

13

এটি একই বিষয়টির জাভা প্রশ্নের উত্তরটি মূলত আমার একটি নির্লজ্জ ক্লোন । দেখা যাচ্ছে যে জুয়েলসিএলআই স্কেল-বান্ধব কারণ এতে স্বয়ংক্রিয় যুক্তি নামকরণের জন্য জাভাবিয়ান শৈলী পদ্ধতিগুলির প্রয়োজন হয় না।

জুয়েলসিএলআই হ'ল কমান্ড-লাইন পার্সিংয়ের জন্য একটি স্কালা-বান্ধব জাভা গ্রন্থাগার যা পরিষ্কার কোড দেয় । এটি আপনার কমান্ড-লাইন প্যারামিটারগুলির জন্য ডায়নামিকভাবে টাইপ-নিরাপদ এপিআই তৈরি করতে টিকা সহ কনফিগার করা প্রক্সিড ইন্টারফেস ব্যবহার করে।

প্যারামিটার ইন্টারফেসের একটি উদাহরণ 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)
    }
  }
}

উপরের ফাইলগুলির অনুলিপি একটি একক ডিরেক্টরিতে সংরক্ষণ করুন এবং জুয়েলসিএলআই 0.6 জারও সেই ডিরেক্টরিতে ডাউনলোড করুন ।

লিনাক্স / ম্যাক ওএস এক্স / ইত্যাদিতে বাশে উদাহরণটি সংকলন করুন এবং চালান:

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

এটিতে আপনি খেয়াল করতে পারেন যে মজাদার একটি অংশটি হ'ল (আরগস: _ *)। স্কালা থেকে জাভা ভারার্গস পদ্ধতিতে কল করার জন্য এটির প্রয়োজন। এটি হ'ল আমি জেসি আইশারের দুর্দান্ত দৈনিক স্কাল ব্লগের দৈনিক- scala.blogspot.com/2009/11/varargs.html থেকে সমাধানটি শিখেছি । আমি ডেইলি স্কালার জন্য অত্যন্ত পরামর্শ দিচ্ছি :)
আলেন ওডিয়া

12

বাহ্যিক নির্ভরতা ছাড়াই প্যারামিটারগুলি কীভাবে পার্স করবেন। দুর্দান্ত প্রশ্ন! আপনি পিকোকলিতে আগ্রহী হতে পারেন ।

প্রশ্নটিতে জিজ্ঞাসা করা সমস্যা সমাধানের জন্য পিকোক্লি বিশেষত ডিজাইন করা হয়েছে: এটি একটি ফাইলে একটি কমান্ড লাইন পার্সিং ফ্রেমওয়ার্ক, যাতে আপনি এটি উত্স আকারে অন্তর্ভুক্ত করতে পারেন । এটি ব্যবহারকারীদের বাহ্যিক নির্ভরতা হিসাবে পিকোক্লি প্রয়োজন ছাড়াই পিকোক্লি-ভিত্তিক অ্যাপ্লিকেশন চালাতে দেয় ।

এটি ক্ষেত্রগুলি টীকা দিয়ে কাজ করে যাতে আপনি খুব কম কোড লিখেন। দ্রুত সংক্ষিপ্তসার:

  • দৃ everything়ভাবে টাইপ করা সমস্ত কিছু - কমান্ড লাইন বিকল্পগুলির পাশাপাশি অবস্থানগত পরামিতি
  • পসিক্স ক্লাস্টারযুক্ত ছোট বিকল্পগুলির জন্য সমর্থন (যাতে এটি হ্যান্ডেলগুলি <command> -xvfInputFileপাশাপাশি করে <command> -x -v -f InputFile)
  • একটি আরটি মডেল যা ন্যূনতম, সর্বাধিক এবং পরিবর্তনশীল সংখ্যক পরামিতিগুলির অনুমতি দেয়, যেমন "1..*","3..5"
  • বয়লারপ্লেট ক্লায়েন্ট কোডটি ন্যূনতম করতে প্রবাহিত এবং কমপ্যাক্ট API
  • subcommands
  • এএনএসআই রঙগুলির সাথে ব্যবহারের সহায়তা

ব্যবহারের সাহায্যের বার্তাটি টীকাগুলির সাথে কাস্টমাইজ করা সহজ (প্রোগ্রামিং ছাড়াই)। উদাহরণ স্বরূপ:

বর্ধিত ব্যবহার সহায়তা বার্তা( উত্স )

কী ধরণের ব্যবহারের সাহায্যের বার্তাগুলি সম্ভব তা দেখানোর জন্য আমি আরও একটি স্ক্রিনশট যুক্ত করে প্রতিহত করতে পারিনি। ব্যবহারের সহায়তা হ'ল আপনার আবেদনের মুখ, তাই সৃজনশীল হন এবং মজা করুন!

পিকোক্লি ডেমো

দাবি অস্বীকার: আমি পিকোকলি তৈরি করেছি। মতামত বা প্রশ্ন খুব স্বাগত। এটি জাভাতে লেখা আছে, তবে স্ক্যালায় এটি ব্যবহার করে কোনও সমস্যা আছে কিনা তা আমাকে জানান এবং আমি এটি সমাধান করার চেষ্টা করব।


1
ডাউনটা কেন? এটিই আমি সচেতন সেই একমাত্র গ্রন্থাগার এটি ওপিতে উল্লিখিত সমস্যা সমাধানের জন্য বিশেষভাবে তৈরি করা হয়েছে: কীভাবে নির্ভরতা যুক্ত করা এড়ানো যায়।
রিমকো পপমা

"অ্যাপ্লিকেশন লেখকদের এটি অন্তর্ভুক্ত করতে উত্সাহিত করুন"। ভাল কাজ.
কেওস

আপনার কি স্কেলার উদাহরণ আছে?
ক্রাঙ্কারবিগডাটা

1
আমি অন্যান্য জেভিএম ভাষার উদাহরণ তৈরি করতে শুরু করেছি: github.com/remkop/picocli/issues/183 প্রতিক্রিয়া এবং অবদান স্বাগত!
রিমকো পপমা

11

আমি জাভা বিশ্ব থেকে এসেছি, আমি আরগস 4 জে পছন্দ করি কারণ এর সাধারণ, স্পেসিফিকেশনটি আরও পাঠযোগ্য (টীকাগুলির জন্য ধন্যবাদ) এবং সুন্দর বিন্যাসিত আউটপুট উত্পাদন করে।

এখানে আমার উদাহরণ স্নিপেট:

সবিস্তার বিবরণী

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.

10

Scala-optparse-আবেদন

আমি মনে করি স্কালা-অপ্টপার্স-অ্যাপ্লিয়েটিভ হ'ল স্কালার সবচেয়ে কার্যকরী কমান্ড লাইন পার্সার লাইব্রেরি।

https://github.com/bmjames/scala-optparse-applicative


README এ ছাড়াও এর কি কোনও উদাহরণ / ডক আছে?
এরিক কাপলুন

1
এটি করে, examplesপরীক্ষার কোডটি পরীক্ষা করে দেখুন
gpampara

8

জ্যাকমন্ডার এছাড়াও রয়েছে (দাবি অস্বীকার: আমি এটি তৈরি করেছি):

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)
    }
  }
}

2
আমার এটা ভাল লেগেছে. এই 'খাঁটি স্কেলা' পার্সারদের একটি পরিষ্কার বাক্য গঠন রয়েছে
টোকোথ

@tactoth এই এক পরীক্ষা, এটি একটি স্পষ্ট সিনট্যাক্স রয়েছে: stackoverflow.com/questions/2315912/...
ব্রুনো Bieth

6

আমি জস্লিনমের স্লাইডটি () পদ্ধতির পছন্দটি করেছিলাম কেবল পরিবর্তনযোগ্য যুদ্ধসমূহ নয়;) সুতরাং সেই পদ্ধতির জন্য একটি অপরিবর্তনীয় উপায়:

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
  }
}


3

প্রয়োজনীয় অবস্থানগত কী প্রতীকগুলির একটি তালিকা, পতাকার মানচিত্র -> কী প্রতীক এবং ডিফল্ট বিকল্পগুলি নিয়ে আমি @ পজোট্রপির সমাধানকে সাধারণীকরণের চেষ্টা করেছি:

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)
}

পতাকাগুলি হ্যান্ডেল করতে (মানগুলি সহ কেবলমাত্র বিকল্প নয়) এবং সংক্ষিপ্ত এবং দীর্ঘ ফর্মগুলির সাথে বিকল্প / পতাকা সংজ্ঞায়িত করার জন্যও আমি এই কোডটির টুকরোটি আপডেট করেছি। যেমন -f|--flags। কটাক্ষপাত gist.github.com/DavidGamba/b3287d40b019e498982c এবং যদি আপনি এটা পছন্দ উত্তর আপডেট করার জন্য বিনা দ্বিধায়। আমি সম্ভবত প্রতিটি মানচিত্র এবং বিকল্প তৈরি করব যাতে আপনি কেবল নামযুক্ত যুক্তি দিয়ে যা প্রয়োজন তা পাস করতে পারেন।
ডেভিডজি

3

আমি আমার পদ্ধতির উপরের উত্তরের উপর ভিত্তি করে (ডেভ 4420 থেকে) এটিকে আরও সাধারণ-উদ্দেশ্য করে উন্নত করার চেষ্টা করেছি।

এটি 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)


2

এখানে একটি স্কালা কমান্ড লাইন পার্সার ব্যবহার করা সহজ। এটি স্বয়ংক্রিয়ভাবে সহায়তা পাঠ্যকে ফর্ম্যাট করে এবং এটি আপনার পছন্দসই প্রকারে স্যুইচ আর্গুমেন্টকে রূপান্তর করে। উভয় সংক্ষিপ্ত POSIX, এবং দীর্ঘ GNU শৈলী সুইচ সমর্থিত। প্রয়োজনীয় আর্গুমেন্ট, alচ্ছিক আর্গুমেন্ট এবং একাধিক মান আর্গুমেন্ট সহ সুইচ সমর্থন করে। এমনকি আপনি কোনও নির্দিষ্ট স্যুইচের জন্য গ্রহণযোগ্য মানগুলির সসীম তালিকাও নির্দিষ্ট করতে পারেন। সুবিধার জন্য লম্বা সুইচ নামগুলি কমান্ড লাইনে সংক্ষিপ্ত করা যেতে পারে। রুবি স্ট্যান্ডার্ড লাইব্রেরিতে বিকল্প পার্সারের মতো।


2

অপশন পার্সারের মতো রুবি আমি কখনই পছন্দ করি না। তাদের ব্যবহার করা বেশিরভাগ বিকাশকারী কখনওই সঠিক ম্যান পৃষ্ঠা লিখেন না তাদের স্ক্রিপ্টগুলির জন্য এবং পার্সারের কারণে পৃষ্ঠাগুলির দীর্ঘ বিকল্পগুলি সঠিক উপায়ে সংগঠিত হয়নি।

পার্লের গেটোপট :: লংয়ের সাথে আমি সবসময় পার্লের জিনিসগুলি করার পছন্দকে পছন্দ করেছি

আমি এটির স্কেল বাস্তবায়নে কাজ করছি। প্রারম্ভিক এপিআই এর মতো কিছু দেখায়:

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)

প্রকল্পটি গিথুব স্কেলা-গেওপশনগুলিতে হোস্ট করা হয়েছে ।


2

আমি স্রেফ আমার সহজ গণনা তৈরি করেছি

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

আমি বুঝতে পারি যে সমাধানের দুটি প্রধান ত্রুটি রয়েছে যা আপনাকে বিভ্রান্ত করতে পারে: এটি স্বাধীনতা (যেমন অন্যান্য গ্রন্থাগারের উপর নির্ভরতা, যে আপনি এত মূল্যবান) এবং অপ্রয়োজনীয়তা (ডিআরওয়াই নীতিমালা, আপনি অপশনের নামটি কেবল একবার টাইপ করেন, স্কেল প্রোগ্রাম হিসাবে) মুছে ফেলে elim পরিবর্তনশীল এবং এটি দ্বিতীয় বার কমান্ড লাইন পাঠ্য টাইপ করুন নির্মূল)।


2

আমি 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

2

এই আমি রান্না। এটি মানচিত্রের একটি তালিকা এবং একটি তালিকা প্রদান করে। তালিকা ইনপুট ফাইলের নামের মতো হয়। মানচিত্রটি স্যুইচ / বিকল্পগুলির জন্য।

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)

স্যুইচগুলি "--t" হতে পারে যা কোন এক্সকে সত্য হিসাবে সেট করা হবে, বা "--x 10" যা এক্সকে "10" এ সেট করা হবে। অন্য সব কিছুই তালিকায় শেষ হবে।

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)
    }
  }
}

1

আমি এই কোডটির পরিষ্কার চেহারা পছন্দ করি ... এখানে একটি আলোচনা থেকে শুকনো: 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)
  }

}

1

সবাই যেমন এখানে পোস্ট করেছে তার নিজস্ব সমাধান আমার, কারণ আমি ব্যবহারকারীর পক্ষে আরও সহজ কিছু লিখতে চেয়েছিলাম: 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)
    }
}

কোনও ভেরিয়েবলকে কিছু সীমানায় জোর করে দেওয়ার জন্য অভিনব বিকল্প নেই, কারণ পার্সারটি এটি করার জন্য সেরা জায়গা বলে আমি মনে করি না।

দ্রষ্টব্য: প্রদত্ত ভেরিয়েবলের জন্য আপনার যত খুশি উরফ থাকতে পারে।


1

আমি গাদা করতে যাচ্ছি। আমি কোডের একটি সাধারণ লাইন দিয়ে এটি সমাধান করেছি। আমার কমান্ড লাইন আর্গুমেন্টগুলি এর মতো দেখাচ্ছে:

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)

আমি তখন আমার কোডে নামযুক্ত পরামিতিগুলির মানগুলি অ্যাক্সেস করতে পারি এবং কমান্ড লাইনে তারা যে ক্রমটি উপস্থিত হয় তা আর প্রাসঙ্গিক নয়। আমি বুঝতে পারি এটি মোটামুটি সহজ এবং উপরে উল্লিখিত সমস্ত উন্নত কার্যকারিতা নেই তবে বেশিরভাগ ক্ষেত্রেই যথেষ্ট বলে মনে হচ্ছে, কেবল কোডের একটি লাইনের প্রয়োজন, এবং বাহ্যিক নির্ভরতা জড়িত না।


1

এখানে আমার 1-লাইনার

    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)

এটি 3 বাধ্যতামূলক আর্গুমেন্ট ড্রপ করে এবং বিকল্পগুলি দেয়। পূর্ণসংখ্যাটি কুখ্যাত -Xmx<size>জাভা বিকল্পের মতো নির্দিষ্টভাবে উপসর্গের সাথে নির্দিষ্ট করা হয়। আপনি বাইনারিগুলি এবং পূর্ণসংখ্যার হিসাবে সহজে পার্স করতে পারেন

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

কিছু আমদানি করার দরকার নেই।


0

দরিদ্র ব্যক্তির দ্রুত এবং নোংরা ওয়ান-লাইনার কী = মান জোড় পার্স করার জন্য:

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

0

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
}

এটি নিম্নলিখিত ব্যবহার তৈরি করবে:

ব্যবহার

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.