Как работает "scala.sys.process" из Scala 2.9?

Я только что посмотрел на новый scala.sys а также scala.sys.process пакеты, чтобы увидеть, если есть что-то полезное здесь. Однако я в полной растерянности.

Кто-нибудь есть пример того, как на самом деле начать процесс?

И, что для меня самое интересное: можете ли вы отделить процессы?

Отдельный процесс будет продолжать выполняться после завершения родительского процесса и является одним из слабых мест Ant.

ОБНОВИТЬ:

Кажется, есть некоторая путаница, что такое отделение. Есть реальный живой пример из моего текущего проекта. Один раз с z-Shell и один раз с TakeCommand:

Z-Shell:

if ! ztcp localhost 5554; then
    echo "[ZSH] Start emulator"
    emulator                        \
    -avd    Nexus-One               \
    -no-boot-anim                   \
    1>~/Library/Logs/${PROJECT_NAME}-${0:t:r}.out   \
    2>~/Library/Logs/${PROJECT_NAME}-${0:t:r}.err   &
    disown
else
    ztcp -c "${REPLY}"
fi;

Take-Command:

IFF %@Connect[localhost 5554] lt 0 THEN
   ECHO [TCC] Start emulator
   DETACH emulator -avd Nexus-One -no-boot-anim
ENDIFF

В обоих случаях он запускается и забывается, эмулятор запускается и будет продолжать работать даже после завершения сценария. Конечно, писать сценарии дважды - пустая трата времени. Поэтому я сейчас заглядываю в Scala для унифицированной обработки процессов без синтаксиса cygwin или xml.

7 ответов

Решение

Первый импорт:

import scala.sys.process.Process

затем создайте ProcessBuilder

val pb = Process("""ipconfig.exe""")

Тогда у вас есть два варианта:

  1. запустить и заблокировать, пока процесс не выйдет

    val exitCode = pb.!
    
  2. запустить процесс в фоновом режиме (отдельно) и получить Process пример

    val p = pb.run
    

    Затем вы можете получить код выхода из процесса с помощью (если процесс все еще выполняется, он блокируется, пока не завершится)

    val exitCode = p.exitValue
    

Если вы хотите обрабатывать ввод и вывод процесса, вы можете использовать ProcessIO:

import scala.sys.process.ProcessIO
val pio = new ProcessIO(_ => (),
                        stdout => scala.io.Source.fromInputStream(stdout)
                          .getLines.foreach(println),
                        _ => ())
pb.run(pio)

Я почти уверен, что отдельные процессы работают просто отлично, учитывая, что вам нужно явно ждать, пока он завершится, и вам нужно использовать потоки, чтобы присматривать за stdout и stderr. Это довольно простой, но это то, что я использовал:

/** Run a command, collecting the stdout, stderr and exit status */
def run(in: String): (List[String], List[String], Int) = {
  val qb = Process(in)
  var out = List[String]()
  var err = List[String]()

  val exit = qb ! ProcessLogger((s) => out ::= s, (s) => err ::= s)

  (out.reverse, err.reverse, exit)
}

Процесс был импортирован из SBT. Вот подробное руководство о том, как использовать библиотеку процессов, как она появляется в SBT.

https://github.com/harrah/xsbt/wiki/Process

Следующая функция позволит легко использовать здесь документы:

def #<<< (command: String) (hereDoc: String) =
{
    val process = Process (command)
    val io = new ProcessIO (
        in  => {in.write (hereDoc getBytes "UTF-8"); in.close},
        out => {scala.io.Source.fromInputStream(out).getLines.foreach(println)},
        err => {scala.io.Source.fromInputStream(err).getLines.foreach(println)})
    process run io
}

К сожалению, я не смог (не успел) сделать это инфиксной операцией. Поэтому предлагаемое соглашение о вызовах:

#<<< ("command") {"""
Here Document data
"""}

Был бы вызов, если бы кто-нибудь мог дать мне подсказку о том, как сделать его более похожим на оболочку:

"command" #<<< """
Here Document data
""" !

Кто-нибудь есть пример того, как на самом деле начать процесс?

import sys.process._ // Package object with implicits!
"ls"!

И, что для меня самое интересное: можете ли вы отделить процессы?

"/path/to/script.sh".run()

Большая часть того, что вы будете делать, связана с sys.process.ProcessBuilderЧерта. Узнай это.

Существуют последствия, которые делают использование менее многословным, и они доступны через объект пакета sys.process, Импортируйте его содержимое, как показано в примерах. Кроме того, взгляните на его скаладок.

Процесс документирования немного лучше был вторым в моем списке в течение двух месяцев. Вы можете вывести мой список из того факта, что я никогда не попал в него. В отличие от большинства вещей, которые я не делаю, это то, что я сказал, я бы сделал, поэтому я очень сожалею о том, что он остается таким же недокументированным, как и когда он прибыл. Меч, готовь себя! Я падаю на тебя!

Если я до сих пор понимаю диалог, один из аспектов исходного вопроса еще не получен:

  1. как "отсоединить" порожденный процесс, чтобы он продолжал выполняться независимо от родительского скрипта scala

Основная трудность заключается в том, что все классы, участвующие в порождении процесса, должны выполняться на JVM, и они неизбежно завершаются при выходе из JVM. Однако обходной путь заключается в косвенном достижении цели путем использования оболочки для "отсоединения" от вашего имени. Следующий скрипт scala, который запускает редактор gvim, работает должным образом:

val cmd = Список (
   "Ла Скала",
   "-E",
   """import scala.sys.process._; "gvim".run; System.exit(0);""")
val proc = cmd.run

Предполагается, что scala находится в PATH, и он (неизбежно) также оставляет выполнение родительского процесса JVM.

Другие вопросы по тегам