Scala入门到精通——第三十节 Scala脚本编程与结束语
本节主要内容
- 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 Personscala> val p=new Person("??????????",27)
p: Person = Person@cf528
而对于一些长串跨行的代码,可能会出现报错,例如:
//本意是要粘贴下面的代码
if(p.age>10) trueelsefalse//但实际情况是这样的
scala> if(p.age>10)| true
res0: AnyVal = truescala> else
<console>:1: error: illegal start of definitionelse^scala> false
那要怎么办呢?在REPL命令行中执行下列命令:
scala> :paste
// Entering paste mode (ctrl-D to finish)if(p.age>10)trueelsefalse// 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 worksheetval 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
- 1
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脚本名称,@ 绑定的是我们输入的参数。!#表示脚本声明头部的结束。在脚本中可以使用任何的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 xuetuwuyouHello 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 columndef 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 parameterdef * = (id, name, street, city, state, zip)}val suppliers = TableQuery[Suppliers]// Definition of the COFFEES tableclass 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 joindef 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 supplierssuppliers += (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 foundq1 foreach println// Perform a join to retrieve coffee names and supplier names for// all coffees costing less than $9.00val q2 = for {c <- coffees if c.price < 9.0s <- 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.
- 1
3 加速代码的执行:
scala脚本在执行的过程中,也是通过编译、执行的步骤来进行的,有时候为加速脚本的执行,意图是将编译后的脚本保存下来,在执行时候如果脚本创建之后没有发生变化的话,则直接使用以前编译好的脚本。实现方式是在脚本声明的时候用-savecompiled。
#!/bin/sh
exec scala -savecompiled "$0" "$@"
!#
println("Hello, world!")
args foreach println
它的原理是在代码第一次执行后,生成相应的jar文件,当下次再执行的便调用该jar文件来执行,第一次执行后生成的jar文件如下:
3. 结束语
这门课程的目的是让大家学完之后能够快速上手spark应用程序开发,希望在学完本课程之后,大家将这门课作为自己学习scala的起点,而非终点。
Scala入门到精通——第三十节 Scala脚本编程与结束语相关推荐
- PreScan快速入门到精通第三十六讲PreScan中使用车道线传感器
车道标记传感器提供有关道路上存在的车道线的信息.这些信息以车道线和扫描线相对于传感器的交叉点的形式提供.车道标记传感器的功能和使用可以在车道保持的例子中找到. 车道标记数据 主要是,车道标记传感器提 ...
- PreScan快速入门到精通第三十四讲基于PreScan进行超声波雷达传感器仿真
超声波传感器是一种基于高频声波(>20 kHz)的收发器.超声波传感器的工作原理与雷达传感器非常相似,通过分析传输信号的回波来评估目标的属性. 超声波传感器在汽车领域得到了广泛的应用.典型的应用 ...
- PreScan快速入门到精通第三十九讲基于车道线识别传感器的车道保持辅助算法Demo讲解
车道保持辅助系统介绍: 什么是车道保持辅助系统? 疲劳和分心是无意中偏离车辆行驶车道线的最常见原因.车道保持辅助系统主动帮助驾驶者将其车辆保持在车道内,避免或者降低事故的发生. 车道保持辅助系统使用一 ...
- PreScan快速入门到精通第三十三讲基于PreScan进行激光雷达传感器仿真
激光扫描器或激光雷达(光探测和测距)有广泛的应用.这些应用包括汽车应用的距离测量和环境测绘. 激光雷达已被用于自适应巡航控制(ACC)系统和自动驾驶系统中应用.通过测量与传感器周围物体的距离,可以得到 ...
- MySQL数据库,从入门到精通:第十四篇——MySQL视图详解
MySQL数据库,从入门到精通:第十四篇--MySQL视图详解 第 14 篇_视图 1. 常见的数据库对象 2. 视图概述 2. 1 为什么使用视图? 2. 2 视图的理解 3. 创建视图 3. 1 ...
- MySQL数据库,从入门到精通:第十二篇——MySQL数据类型详解
MySQL数据库,从入门到精通:第十二篇--MySQL数据类型详解 第 12 章_MySQL数据类型精讲 1. MySQL中的数据类型 2. 整数类型 2. 1 类型介绍 2. 2 可选属性 2. 2 ...
- Oracle数据库从入门到精通系列之十八:Oracle进程
Oracle数据库从入门到精通系列之十八:Oracle进程 一.Oracle进程 二.服务器进程server process 三.后台进程background process 四.从属进程(slave ...
- javaSE从入门到精通的二十万字总结(一)
目录 前言 1. 面向对象 1.1 final关键字 1.2 抽象类 1.3 接口 1.4 接口与抽象类结合 1.5 接口的作用 1.6 包和import 1.7 访问控制权限 1.8 Object类 ...
- php flock 都是true_PHP从入门到精通(三)PHP语言基础
PHP从入门到精通(三)PHP语言基础 一.PHP标记风格 PHP支持4种标记风格 1.XML风格.(推荐使用) <?phpecho "这是XML分割的标记"; ?> ...
最新文章
- __add__,关于运算符重载(用户权限)
- 网站优化只需五步技巧分享推广无界限
- Android之自定义View以及画一个时钟
- 014箱子开合并移动
- 利用Python延迟初始化提升性能
- hive解决数据倾斜问题_Hive数据倾斜和解决办法
- php 降低图像大小,PHP图像重新调整大小
- 你今天volatile了吗?--慎重使用
- 为什么选择Bootstrap
- 关于SharePoint V3网站老弹出“此网站需要运行以下载项:'Microsoft Corporation'中的'name.dll'......”的3种解决办法...
- paip..net VS2010提示当前上下文中不存在名称的解决
- 推荐一个php Zend Guard解密工具 G-DeZender 本地版
- 苹果手机描述文件服务器地址是什么,iPhone|iOS设备描述文件扫盲是什么?有什么用?...
- 华为eNSP-ISIS理论+实验配置
- 史上最全的C++/游戏开发面试问题总结(一)——C++基础
- oracle ko16mswin949,PRM DUL Oracle数据库恢复的最后一步
- matlab中多元线性回归regress函数精确剖析(附实例代码)
- 【无标题】2022年施工员-设备方向-通用基础(施工员)考试模拟100题及模拟考试
- UE5神通--POI解决方案
- 重拾java基础知识总结(超级经典)
热门文章
- [leetcode] 160.相交链表
- plsql怎么用字段查表明_如何将oracle表中的字段类型、字段注释说明、字段名一起查询出来...
- 通用无线设备对码软件_电动车上的无线电池管理系统wBMS
- activemq5.14 mysql_activemq5.14+zookeeper3.4.9实现高可用
- Tomcat服务安装与部署(安装与优化)
- Linux远程访问及控制(SSH、TCP Wrappers 访问控制)
- java keypad game,Take character and return the Keypad equivalant
- 智能水杯设计方案_智能水杯盖方案开发
- php转字,php汉字如何转数字
- 波特率_不同波特率CAN总线系统如何进行数据收发