概述
太长不看版
在 scala 中调用外部命令行程序非常简单,只需要导入 sys.process 包,并在需要调用的命令行外加双引号,并在行尾加 ! 号,如果想获得标准输出,就在行尾加 !! 号,如果需要管道或者重定向,请使用 #| 或者 #> 操作符,并注意在 #> 后面不能直接加文件名,需要使用 java.io.File 对象(关于如何快速运行 scala 交互式编程环境,请参考 如何利用 sbt 运行 Scala REPL )。举例:
// 导入需要的依赖
import sys.process._
import java.io.File
// 非阻塞式,使用 run 方法立即返回 scala.sys.process.Process 对象,并且外部命令同时执行
val process: Process = "ls -la".run
// 执行 ls -la 并且获取 exit code
val exitcode = "ls -la" !
// 执行 ls -la 并且获取标准输出
val stdout = "ls -la" !!
// 执行 ls -la . no_such_file.txt 并同时获取 exitcode,标准输出和标准错误
val n, e = new StringBuilder
val logger = ProcessLogger( l => n.append(l).append("n"), l => e.append(l).append("n"))
val exitcode = "ls -la . no_such_file.txt" ! logger
// bash 管道操作
val m = "ls -la" #| "grep foo" !!
// 输出重定向
"ls -la" #> new File("ls_output.txt") !
正文
我们在编写程序时经常会遇到需要在程序中调用外部命令的情况,scala 语言也提供了让程序员调用外部命令的功能。本文不但介绍如何在 scala 中调用外部命令行(比如 Linux 下的 bash 命令),也会讲解如何获取外部命令的标准输出、错误输出以及如何使用管道和重定向。关于如何快速运行 scala 交互式编程环境,请参考 如何利用 sbt 运行 Scala REPL
1.1 非阻塞式调用,获取 scala.sys.process.Process 对象
首先,导入 sys.process 包
scala> import sys.process._
import sys.process._
使用 run 方法获取进程对象
scala> val process: Process = "ls -la".run
process: scala.sys.process.Process = scala.sys.process.ProcessImpl$SimpleProcess@714975fd
total 24
drwxr-xr-x
7 kongl
staff
224 12 10 12:11 .
drwx------@ 458 kongl
staff
14656 12 10 12:11 ..
-rw-r--r--
1 kongl
staff
9 12 10 12:11 and_more.txt
-rw-r--r--
1 kongl
staff
12 12 10 12:11 bar.txt
-rw-r--r--
1 kongl
staff
12 12 10 12:11 foo.txt
drwxr-xr-x
3 kongl
staff
96 12 10 12:11 project
drwxr-xr-x
5 kongl
staff
160 12 10 12:17 target
1.2 在 scala 中调用外部命令并获取 exit code
首先,导入 sys.process 包
scala> import sys.process._
import sys.process._
在需要调用的命令行外加双引号,并在行尾加 ! 号
scala> val exitcode = "ls -al" !
warning: there was one feature warning; for details, enable `:setting -feature' or `:replay -feature'
total 24
drwxr-xr-x
7 kongl
staff
224 12 10 12:11 .
drwx------@ 458 kongl
staff
14656 12 10 12:11 ..
-rw-r--r--
1 kongl
staff
9 12 10 12:11 and_more.txt
-rw-r--r--
1 kongl
staff
12 12 10 12:11 bar.txt
-rw-r--r--
1 kongl
staff
12 12 10 12:11 foo.txt
drwxr-xr-x
3 kongl
staff
96 12 10 12:11 project
drwxr-xr-x
5 kongl
staff
160 12 10 12:17 target
exitcode: Int = 0
scala> print(exitcode)
0
2. 在 scala 中调用外部命令并获取标准输出和错误输出
2.1 只需要获取标准输出的情形
如果只需要标准输出,那么非常简单,只需要把上个例子中的 ! 替换为 !! 即可,例如
scala> import sys.process._
import sys.process._
scala> val stdout = "ls -la" !!
warning: there was one feature warning; for details, enable `:setting -feature' or `:replay -feature'
stdout: String =
"total 24
drwxr-xr-x
7 kongl
staff
224 12 10 12:23 .
drwx------@ 458 kongl
staff
14656 12 10 12:11 ..
-rw-r--r--
1 kongl
staff
9 12 10 12:11 and_more.txt
-rw-r--r--
1 kongl
staff
12 12 10 12:11 bar.txt
-rw-r--r--
1 kongl
staff
12 12 10 12:11 foo.txt
drwxr-xr-x
4 kongl
staff
128 12 10 12:31 project
drwxr-xr-x
5 kongl
staff
160 12 10 12:17 target
"
scala> print(stdout)
total 24
drwxr-xr-x
7 kongl
staff
224 12 10 12:23 .
drwx------@ 458 kongl
staff
14656 12 10 12:11 ..
-rw-r--r--
1 kongl
staff
9 12 10 12:11 and_more.txt
-rw-r--r--
1 kongl
staff
12 12 10 12:11 bar.txt
-rw-r--r--
1 kongl
staff
12 12 10 12:11 foo.txt
drwxr-xr-x
4 kongl
staff
128 12 10 12:31 project
drwxr-xr-x
5 kongl
staff
160 12 10 12:17 target
2.2 需要同时获取标准输出和错误输出的情形
如果需要同时获取标准输出和错误输出,那我们需要用到 ProcessLogger 类,例如
scala> import sys.process._
import sys.process._
scala> val n, e = new StringBuilder
n: StringBuilder =
e: StringBuilder =
scala> val logger = ProcessLogger( l => n.append(l).append("n"), l => e.append(l).append("n"))
logger: scala.sys.process.ProcessLogger = scala.sys.process.ProcessLogger$$anon$1@25968d9c
scala> val exitcode = "ls -la . no_such_file.txt" ! logger
exitcode: Int = 1
scala> print(exitcode)
1
scala> print(n)
.:
total 24
drwxr-xr-x
7 kongl
staff
224 12 10 12:23 .
drwx------@ 458 kongl
staff
14656 12 10 12:11 ..
-rw-r--r--
1 kongl
staff
9 12 10 12:11 and_more.txt
-rw-r--r--
1 kongl
staff
12 12 10 12:11 bar.txt
-rw-r--r--
1 kongl
staff
12 12 10 12:11 foo.txt
drwxr-xr-x
4 kongl
staff
128 12 10 12:31 project
drwxr-xr-x
5 kongl
staff
160 12 10 12:17 target
scala> print(e)
ls: no_such_file.txt: No such file or directory
3. 使用管道和重定向
3.1 如何使用管道
在 scala 中调用 shell 命令,我们不能直接在命令行中使用管道,这是因为 scala 在调用命令时并不会启动 bash 环境,而管道和重定向是 bash 支持的功能。例如,直接运行 “ls -la | grep foo” 我们得到如下报错信息:
scala> import sys.process._
import sys.process._
scala> "ls -la | grep foo" !!
warning: there was one feature warning; for details, enable `:setting -feature' or `:replay -feature'
ls: foo: No such file or directory
ls: grep: No such file or directory
ls: |: No such file or directory
java.lang.RuntimeException: Nonzero exit value: 1
at scala.sys.package$.error(package.scala:30)
at scala.sys.process.ProcessBuilderImpl$AbstractBuilder.slurp(ProcessBuilderImpl.scala:138)
at scala.sys.process.ProcessBuilderImpl$AbstractBuilder.$bang$bang(ProcessBuilderImpl.scala:108)
... 36 elided
因此,我们需要使用 scala 语言提供的 #| 操作符,例如:
scala> val m = "ls -la" #| "grep foo" !!
warning: there was one feature warning; for details, enable `:setting -feature' or `:replay -feature'
m: String =
"-rw-r--r--
1 kongl
staff
12 12 10 12:11 foo.txt
"
scala> print(m)
-rw-r--r--
1 kongl
staff
12 12 10 12:11 foo.txt
也可以多个 #! 连用,例如
scala> val m = "ls -la" #| "grep txt" #| "wc -l" !!
warning: there was one feature warning; for details, enable `:setting -feature' or `:replay -feature'
m: String =
"
3
"
scala> print(m)
3
3.2 如何使用重定向
和使用管道类似,scala 为标准输出重定向提供了 #> 操作符,需要注意的是,在 #> 后面不能直接加文件名,需要使用 File 对象,例如:
scala> import sys.process._
import sys.process._
scala> import java.io.File
import java.io.File
scala> "ls -la" #> new File("ls_output.txt") !
warning: there was one feature warning; for details, enable `:setting -feature' or `:replay -feature'
res31: Int = 0
scala> "cat ls_output.txt" !!
warning: there was one feature warning; for details, enable `:setting -feature' or `:replay -feature'
res32: String =
"total 24
drwxr-xr-x
8 kongl
staff
256 12 10 15:28 .
drwx------@ 458 kongl
staff
14656 12 10 12:11 ..
-rw-r--r--
1 kongl
staff
9 12 10 12:11 and_more.txt
-rw-r--r--
1 kongl
staff
12 12 10 12:11 bar.txt
-rw-r--r--
1 kongl
staff
12 12 10 12:11 foo.txt
-rw-r--r--
1 kongl
staff
0 12 10 15:28 ls_output.txt
drwxr-xr-x
4 kongl
staff
128 12 10 12:31 project
drwxr-xr-x
5 kongl
staff
160 12 10 12:17 target
"
3.3 其他 bash 操作符对应
#<
输入重定向
#>
输出重定向
#>>
追加输出重定向
#&&
和
#!!
或
参考链接
- How to execute (exec) external system commands in Scala
- Scala: How to handle the STDOUT and STDERR of external commands
- ProcessLogger
最后
以上就是大胆砖头为你收集整理的如何用 scala 调用外部命令、重定向及使用管道?太长不看版正文的全部内容,希望文章能够帮你解决如何用 scala 调用外部命令、重定向及使用管道?太长不看版正文所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复