Scala入门到精通——第三十节 Scala脚本编程与结束语
2015-08-17 16:40
387 查看
本节主要内容
REPL命令行高级使用使用Scala进行Linux脚本编程
结束语
1. REPL命令行高级使用
在使用REPL命令行时,有时候我们需要粘贴的代码比较大,而普通的粘贴可能会些一些问题,比如中文粘贴会出现乱码、多行代码粘贴时会出错,此时需要用到REPL的高级功能。在日常开发过程中,我们粘贴多行代码的时候会遇到下列问题://本意是要粘贴下面两行代码 class Person(val name:String,val age:Int) val p=new Person("摇摆少年梦",27) //直接在REPL命令行粘贴的话,会出现下面情况 //1 不会一次性粘入,而是分作两行 //2 中文出现乱码 scala> class Person(val name:String,val age:Int) defined class Person scala> val p=new Person("??????????",27) p: Person = Person@cf528
而对于一些长串跨行的代码,可能会出现报错,例如:
//本意是要粘贴下面的代码 if(p.age>10) true else false //但实际情况是这样的 scala> if(p.age>10) | true res0: AnyVal = true scala> else <console>:1: error: illegal start of definition else ^ scala> false
那要怎么办呢?在REPL命令行中执行下列命令:
scala> :paste // Entering paste mode (ctrl-D to finish) if(p.age>10) true else false // Exiting paste mode, now interpreting. res3: Boolean = true
先输入:paste,然后按ctr+v键,可以正常粘贴内容,中文也不会出现乱码了:
scala> :paste // Entering paste mode (ctrl-D to finish) class Person(val name:String,val age:Int) val p=new Person("摇摆少年梦",27) // Exiting paste mode, now interpreting. defined class Person p: Person = Person@1924b38
另外,在实际开发过程中,有些人会认为这种处理方式非常繁琐,Scala的创建者也为我们考虑过这个问题了,我们也可以在scala IDE for eclipse (在Intellij IDEA 中也有这个功能) 里面利用REPL命令行,使用方式是创建scala worksheet,创建方式如下:
1 点击相应的包,然后右键,在new菜单中选择 scala worksheet
2 在文件中输入相应的scala语句,worksheet会自动打印出相应的结果
但是worksheet对中文的支持很不友好,例如下面的代码:
case class Person(val name:String,val age:Int) object ScalaREPL { println("Scala worksheet") //> Scala worksheet val p=new Person("摇摆少年梦",27) //> p : cn.scala.xtwy.jdbc.Person = Person(鎽囨憜灏戝勾姊�27) }
worksheet最终得到的中文是乱码,因此在实际进行语言特性测试的时候尽量避免中文
scala中还有很多我们实际中没有接触过的命令,可以用 :help命令查看REPL现在支持的所有命令:
scala> :help All commands can be abbreviated, e.g. :he instead of :help. Those marked with a * have more detailed help, e.g. :help imports. :cp <path> add a jar or directory to the classpath :help [command] print this summary or command-specific help :history [num] show the history (optional num is commands to show) :h? <string> search the history :imports [name name ...] show import history, identifying sources of names :implicits [-v] show the implicits in scope :javap <path|class> disassemble a file or class name :load <path> load and interpret a Scala file :paste enter paste mode: all input up to ctrl-D compiled tog ether :power enable power user mode :quit exit the interpreter :replay reset execution and replay all previous commands :reset reset the repl to its initial state, forgetting all s ession entries :sh <command line> run a shell command (result is implicitly => List[Str ing]) :silent disable/enable automatic printing of results :type [-v] <expr> display the type of an expression without evaluating it :warnings show the suppressed warnings from the most recent lin e which had any
2. 使用Scala进行Linux脚本编程
本节Linux脚本内容大部分来源于scala cookbook,部分经过本人修改以在Ubuntu Linux上进行演示。我们在第一节中提到,Scala不仅仅可以进行大规模分布式应用程序开发(例如Spark内存计算框架),也可以进行服务器端脚本编程即它可以替代Linux中的shell (Bourne Shell, Bash)或其它如 Perl, PHP, Ruby等可用于服务器端脚本编程的语言。下面给出的是一个简单示例(前提是要有linux操作系统,本节所有示例都是在ubuntu Linux下运行的):
#!/bin/sh exec scala "$0" "$@" !# println("HellO,Linux World")
将上面的内容保存为hello.sh文件,然后用下列命令增加其执行权限:
root@sparkmaster:/home/zhouzhihu/scalaLearning# chmod +x hello.sh root@sparkmaster:/home/zhouzhihu/scalaLearning# ./hello.sh HellO,Linux World
可以看到我们第一个服务器脚本已经运行成功。前面的代码中,#!符号表示的是Unix shell脚本的开始,它会调用Unix Bourne shell。exce命令是内置的shell,表示需要执行scala 命令,其中0绑定的是hello.sh脚本名称,0绑定的是hello.sh脚本名称,@ 绑定的是我们输入的参数。!#表示脚本声明头部的结束。在脚本中可以使用任何的scala语法,例如:
#!/bin/sh exec scala "$0" "$@" !# class Person(val firstName:String,val secondName:String){ override toString()="firstName:"+firstName+",secondName:"+secondName } println(new Person("john","Barake"))
上述代码执行结果:
root@sparkmaster:/home/zhouzhihu/scalaLearning# ./person.sh firstName:john,secondName:Barake
除此之外,我们还可以定义应用程序对象,可以扩展自App,也可以实现自己的Main方法,例如:
#!/bin/sh exec scala "$0" "$@" !# object Hello extends App { println("Hello Ubuntu Linux 10.04") //如果后面带参数的话,可以捕获所有的参数 args.foreach(println) } Hello.main(args)
下面给出的是不带参数的执行结果:
root@sparkmaster:/home/zhouzhihu/scalaLearning# ./HelloApp.sh Hello Ubuntu Linux 10.04
下面给出的是带参数的执行结果,如:
root@sparkmaster:/home/zhouzhihu/scalaLearning# ./HelloApp.sh hello xuetuwuyou Hello Ubuntu Linux 10.04 hello xuetuwuyou
当然,还可以实现自己的main方法,如:
#!/bin/sh exec scala "$0" "$@" !# object Hello { def main(args: Array[String]) { println("Hello, world") args.foreach(println) } } Hello.main(args)
同extends App是一样的。
如果脚本中需要应用到第三方库的话,可以采用下列方式进行包引入:
#!/bin/sh exec scala -classpath "lib/slick_2.11_2.1.0.jar:lib/mysql-connector-java-5.1.18-bin.jar" "$0" "$@" !# import scala.slick.driver.MySQLDriver.simple._ object CoffeeExample extends App { class Suppliers(tag: Tag) extends Table[(Int, String, String, String, String, String)](tag, "SUPPLIERS") { def id = column[Int]("SUP_ID", O.PrimaryKey) // This is the primary key column def name = column[String]("SUP_NAME") def street = column[String]("STREET") def city = column[String]("CITY") def state = column[String]("STATE") def zip = column[String]("ZIP") // Every table needs a * projection with the same type as the table's type parameter def * = (id, name, street, city, state, zip) } val suppliers = TableQuery[Suppliers] // Definition of the COFFEES table class Coffees(tag: Tag) extends Table[(String, Int, Double, Int, Int)](tag, "COFFEES") { def name = column[String]("COF_NAME", O.PrimaryKey) def supID = column[Int]("SUP_ID") def price = column[Double]("PRICE") def sales = column[Int]("SALES") def total = column[Int]("TOTAL") def * = (name, supID, price, sales, total) // A reified foreign key relation that can be navigated to create a join def supplier = foreignKey("SUP_FK", supID, suppliers)(_.id) } val coffees = TableQuery[Coffees] Database.forURL("jdbc:mysql://localhost:3306/slick", "root", "123", driver = "com.mysql.jdbc.Driver") withSession { implicit session => // Create the tables, including primary and foreign keys (suppliers.ddl ++ coffees.ddl).create // Insert some suppliers suppliers += (101, "Acme, Inc.", "99 Market Street", "Groundsville", "CA", "95199") suppliers += (49, "Superior Coffee", "1 Party Place", "Mendocino", "CA", "95460") suppliers += (150, "The High Ground", "100 Coffee Lane", "Meadows", "CA", "93966") // Insert some coffees (using JDBC's batch insert feature, if supported by the DB) coffees ++= Seq( ("Colombian", 101, 7.99, 0, 0), ("French_Roast", 49, 8.99, 0, 0), ("Espresso", 150, 9.99, 0, 0), ("Colombian_Decaf", 101, 8.99, 0, 0), ("French_Roast_Decaf", 49, 9.99, 0, 0)) coffees foreach { case (name, supID, price, sales, total) => println(" " + name + "\t" + supID + "\t" + price + "\t" + sales + "\t" + total) } val q1 = for (c <- coffees) yield LiteralColumn(" ") ++ c.name ++ "\t" ++ c.supID.asColumnOf[String] ++ "\t" ++ c.price.asColumnOf[String] ++ "\t" ++ c.sales.asColumnOf[String] ++ "\t" ++ c.total.asColumnOf[String] // The first string constant needs to be lifted manually to a LiteralColumn // so that the proper ++ operator is found q1 foreach println // Perform a join to retrieve coffee names and supplier names for // all coffees costing less than $9.00 val q2 = for { c <- coffees if c.price < 9.0 s <- suppliers if s.id === c.supID } yield (c.name, s.name) } } //这点与一般的应用程序不同 CoffeeExample.main(args)
通过上述代码不难发现,脚本编程与一般的Scala应用程序开发有着非常多的相似之处,不同之处仅在于在脚本编程需要加入下面这样的样板代码
#!/bin/sh //样板代码 exec scala -classpath "lib/slick_2.11_2.1.0.jar:lib/mysql-connector-java-5.1.18-bin.jar" "$0" "$@" !# //样板代码 .................... CoffeeExample.main(args) //样板代码
有时候,我们也需要对命令行参数进行捕获(例如判断命令行的个数或输入的参数类型等),然后进行相应的操作,前面已经演示了如何打印输出命令行参数,这里我们更多实际中可能会遇到的一些经典案例:
1 判断输入参数的个数,不满足要求则给出提示
#!/bin/sh exec scala "$0" "$@" !# if (args.length != 2) { Console.err.println("Usage: replacer <search> <replace>") System.exit(1) } val searchPattern = args(0) val replacePattern = args(1) println(s"Replacing $searchPattern with $replacePattern ...")
执行结果如下:
root@sparkmaster:/home/zhouzhihu/scalaLearning# ./argsNumberDemo.sh xuetuwu xuetuwuyou Replacing xuetuwu with xuetuwuyou ... root@sparkmaster:/home/zhouzhihu/scalaLearning# ./argsNumberDemo.sh Usage: replacer <search> <replace>
2 交互式命令行,提示用户输入
#!/bin/sh exec scala "$0" "$@" !# // write some text out to the user with Console.println Console.println("Hello") // Console is imported by default, so it's not really needed, just use println println("World") // readLine lets you prompt the user and read their input as a String val name = readLine("What's your name? ") // readInt lets you read an Int, but you have to prompt the user manually print("How old are you? ") val age = readInt() // you can also print output with printf println(s"Your name is $name and you are $age years old.")
下面给出的是其执行结果:
root@sparkmaster:/home/zhouzhihu/scalaLearning# ./promptDemo.sh Hello World What's your name? yaobaishaonianmeng How old are you? 27 Your name is yaobaishaonianmeng and you are 27 years old.
3 加速代码的执行:
scala脚本在执行的过程中,也是通过编译、执行的步骤来进行的,有时候为加速脚本的执行,意图是将编译后的脚本保存下来,在执行时候如果脚本创建之后没有发生变化的话,则直接使用以前编译好的脚本。实现方式是在脚本声明的时候用-savecompiled。
#!/bin/sh exec scala -savecompiled "$0" "$@" !# println("Hello, world!") args foreach println
它的原理是在代码第一次执行后,生成相应的jar文件,当下次再执行的便调用该jar文件来执行,第一次执行后生成的jar文件如下:
3. 结束语
本节内容是scala入门到精通系列课程的最后一节,通过本课程,我相信可以让大家成为一个中级scala语言开发者。Scala语言功能非常强大,其中内容还有很多,还有许多内容我们没有涉及,例如scala 的GUI编程、Scala的定界延续等,但这些功能在实际开发中应用的并不是特别广泛,特别是Scala GUI编程,我们知道java在GUI编程方面并不是它的强项,scala语言也是如此。这门课程的目的是让大家学完之后能够快速上手spark应用程序开发,希望在学完本课程之后,大家将这门课作为自己学习scala的起点,而非终点。作为本门课程的授课人,这也不是我的终点,而是我的起点,在后面我会接着对scala语言、Spark大数据处理技术进行更深入的学习和研究,并将自己的学习心得与体会分享给大家。在后面我将陆续开设下列几门课程:
Spark修炼之道(基础篇)——Linux基础(12讲)、Akka分布式编程(8讲) Spark修炼之道(进阶篇)——Spark入门到精通(30讲) Spark修炼之道(实战篇)——Spark应用开发实战篇(20讲) Spark修炼之道(高级篇)——Spark源码解析(50讲)
该课程针对没有基础的朋友,从Linux开始讲起,然后介绍Akka框架如何进行分布式编程,再此基础上对Spark进行介绍。(基础篇)、(进阶篇)、(实战篇)及(高级篇)采用的是并发方式编写(^-^),希望想学习大数据处理技术的朋友可以关注我的博客或微信公众号。
添加公众微信号,可以了解更多最新Spark、Scala相关技术资讯
相关文章推荐
- 华为上机题之输出身高差值最小的俩个人
- c++builder 多线程
- java多线程中关于原子操作
- OSChina 的URL类的源代码重写过程
- JAVA随笔篇二(深入分析JAVA简单类型、String和对象的值传递和引用传递)
- python学习:IndentationError:expected an indented block错误解决
- Java中使用FTPClient解析文件
- Python matplotlib 画图相关
- Java 泛型
- 文本编辑器之editplus
- php利用api搜索下载it-ebooks.info上图书
- 编写高质量代码改善C#程序的157个建议——建议59:不要在不恰当的场合下引发异常
- 02第一个C语言程序
- C++面试问题
- C#读写文件
- 如何阅读源代码
- myFocus代码库使用方法总结
- java bean对象去掉所以属性两边空格
- 【案例】小心,apc可能导致php-fpm罢工!
- matlab基础