【问题标题】:Execute an SBT command from a script从脚本执行 SBT 命令
【发布时间】:2014-07-10 03:06:28
【问题描述】:

*决定开始赏金并删除不需要的信息

我想在 SBT 控制台中运行一个脚本,该脚本将在最后运行 SBT 命令。如何做到这一点

我编写了一个脚本,允许我执行 shell 命令。输入sbt 然后path/to/my-script start 给我这个错误:/bin/sh: start command not found

但是path/to/my-script sbt start 工作正常

sbt 插件(例如these)或自定义任务在这种情况下不起作用的原因

  • 脚本不是用 scala 编写的

快速编辑

*我更愿意从脚本执行start,而不是使用自定义任务/命令来运行我的脚本

更多信息如下


我将逐步解释我想做的事情(我正在做的事情对你来说可能听起来很傻,但请阅读我对 Etan 的回复):

  1. 在我的控制台中输入 sbt 将调用 SBT 控制台

  2. 我不想输入start,而是想运行一个脚本,该脚本将执行与项目没有直接关系的其他事情,然后在完成后为我调用start

对脚本不太熟悉,脚本可以调用#!/bin/sh 命令,所以我想我想做的是调用#!/bin/sh/<*this-sbt-console*> 命令(如果可能的话)

即使我可以让脚本在终端上打印 start 并在完成后调用 enter/return 键,这样的解决方法也足够了

其他信息:

  • 不使用任何特定框架
  • SBT 版本 = 0.13+

【问题讨论】:

  • 您的脚本作为 scala 脚本运行,其参数通过?为什么要在 sbt 提示符下运行它? sbt 不是为您提供了更直接地运行 scala 脚本的方法吗?
  • @EtanReisner 如上所述: 1. 我使用start 作为示例 2. 我也使用那个小的 Scala 脚本作为示例(实际的脚本更长并且在不同的语言) 3. 还有很多事情要做(见 1 和 2) 4. 我想了解更多关于我使用的 Scala 工具的信息,方法是让我的手有点脏
  • sbt 是一个构建工具。是的,它有一个console 任务,它可以让你在REPL 中使用你项目的类路径和你自己的代码中的任何类,但是这与让sbt 执行bash 文件有什么关系呢?我不明白你在这里想要达到什么目的......所以你能扩展吗?顺便说一句,当您使用path/to/my-script sbt start 时,sbt 与它无关...... bash 文件使用 2 个参数(“sbt”和“start”)执行 scala REPL。 PS.你的示例代码有错误
  • @giladhoch 如果我在 SBT REPL 中并输入 start,它将运行我的应用程序。有没有办法从脚本中做到这一点?这很奇怪,因为我可以在 REPL 中使用 sbt start 运行脚本,但即使我已经在 REPL 中,单独使用 start 也不起作用(请参阅上面的错误)
  • 我还是不明白。为什么你(认为你)需要 sbt?该脚本执行 Scala REPL,它与 SBT 控制台不同。因此,当您在命令行中键入path/to/my-script sbt start 时,shell 将查看第一个参数 (path/to/my-script) 并在传递其他参数 ( sbt&start) 作为参数。当您键入sbt 然后path/to/my-script start 时,您将调用SBT 控制台,它将path/to/my-script&start 作为参数除外。为什么你会期望结果是一样的?

标签: bash shell scala sbt


【解决方案1】:

为了能够执行脚本并在该脚本完成后继续执行另一个 sbt 命令,一种方法是实现一个自定义 sbt 命令,该命令执行以下操作:

  1. 执行作为其第一个参数提供的外部进程,将任何其他参数传递给该进程。
  2. 等待外部进程完成。
  3. 外部进程完成后,执行另一个 sbt 命令。

这在Build.scala 文件中得到了证明:

import sbt._
import Keys._

// imports standard command parsing functionality
import complete.DefaultParsers._

object CommandExample extends Build {
  // Declare a project, adding new commands.
  lazy override val projects = Seq(root)
  lazy val root = Project("root", file(".")) settings(
    commands ++= Seq(start, customStart)
  )

  // A fake "start" command.
  def start = Command.command("start") { state =>
    println("Fake start command executed.")
    state
  }

  // A command that executes an external command before executing the "start" command. 
  // The name of the external command is the first parameter.
  // Any additional parameters are passed along to the external command.
  def customStart = Command.args("customStart", "<name>") { (state, args) =>
    if (args.length > 0) {
      val externalCommand = args.mkString(" ")
      println(s"Executing '$externalCommand'")
      externalCommand !
    }
    "start" :: state
  }
}

这是一个示例执行:

$ sbt
[info] Loading project definition from /home/fernando/work/github/fernandoacorreia/so24565469/project
[info] Set current project to hello (in build file:/home/fernando/work/github/fernandoacorreia/so24565469/)
> customStart ls -la
Executing 'ls -la'
total 40
drwxr-xr-x  6 fernando fernando 4096 Jul  8 10:52 .
drwxr-xr-x 27 fernando fernando 4096 Jul  8 08:51 ..
-rw-r--r--  1 fernando fernando   95 Jul  8 10:47 build.sbt
drwxr-xr-x  8 fernando fernando 4096 Jul  8 08:58 .git
-rw-r--r--  1 fernando fernando  203 Jul  8 09:04 .gitignore
-rw-r--r--  1 fernando fernando 1082 Jul  8 08:51 LICENSE
drwxr-xr-x  3 fernando fernando 4096 Jul  8 10:51 project
-rw-r--r--  1 fernando fernando  111 Jul  8 08:51 README.md
drwxr-xr-x  3 fernando fernando 4096 Jul  8 08:57 src
drwxr-xr-x  2 fernando fernando 4096 Jul  8 10:52 target
Fake start command executed.
> 

作为参数传递给customStart 的外部命令可以是任何可执行命令,例如二进制文件或 shell 脚本。

要了解有关创建命令的更多信息,请参阅Commands documentation page

要了解有关执行外部进程的更多信息,请参阅External Processes documentation page

完整示例可在this GitHub repository 下载。

由于 sbt 执行脚本(作为子进程),该脚本无法在原始(父)sbt 进程上执行命令。

可以将脚本的输出捕获到stdout 或文件中,并让 sbt 命令执行脚本生成的任意命令,但这有点令人费解。

另一种方法是颠倒执行顺序。不是让sbt 执行脚本,而是首先直接从shell 执行脚本,然后脚本将执行sbt 命令。

例如,这个脚本:

#!/bin/bash
echo "Running custom script"
# Insert commands here
sbt start

产生这个输出:

$ ./script 
Running custom script
[info] Loading project definition from /home/fernando/work/github/fernandoacorreia/so24565469/project
[info] Set current project to hello (in build file:/home/fernando/work/github/fernandoacorreia/so24565469/)
Fake start command executed.

【讨论】:

  • 有没有办法从脚本中执行start?那是不可能的吗?或者您是否知道任何其他不涉及从自定义任务/命令运行脚本的解决方法?
  • 如果脚本作为子进程运行,它不能在其父进程的上下文中执行命令。理论上,可以创建一个 sbt 命令,而不是仅仅等待脚本完成,而是打开某种通道,从脚本​​接收消息并在父进程的上下文中执行它们,但这非常复杂、复杂和脆弱。我在有关如何反转执行顺序的问题中添加了更多信息,这可能是一种替代方法。
【解决方案2】:

正如您所说“有没有办法告诉脚本在终端上写一些东西并按回车/回车键?”

是的 - 有点老套但非常有效的解决方案是一个名为 expect 的小程序。

http://www.thegeekstuff.com/2010/10/expect-examples/

http://www.admin-magazine.com/Articles/Automating-with-Expect-Scripts

它可以让你做任何你可以从键盘上做的事情,但是是自动的。它就像一个用于 UNIX 命令提示符的宏播放引擎。

【讨论】:

  • 您能补充更多细节吗?我试过spawn,但没用。您将如何简单地写出start 并使用expect 执行它?
猜你喜欢
  • 2012-10-07
  • 2011-10-07
  • 2016-12-07
  • 2020-04-15
  • 2023-03-06
  • 2013-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多