Как работает "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""")
Тогда у вас есть два варианта:
запустить и заблокировать, пока процесс не выйдет
val exitCode = pb.!
запустить процесс в фоновом режиме (отдельно) и получить
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.
Следующая функция позволит легко использовать здесь документы:
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
, Импортируйте его содержимое, как показано в примерах. Кроме того, взгляните на его скаладок.
Процесс документирования немного лучше был вторым в моем списке в течение двух месяцев. Вы можете вывести мой список из того факта, что я никогда не попал в него. В отличие от большинства вещей, которые я не делаю, это то, что я сказал, я бы сделал, поэтому я очень сожалею о том, что он остается таким же недокументированным, как и когда он прибыл. Меч, готовь себя! Я падаю на тебя!
Если я до сих пор понимаю диалог, один из аспектов исходного вопроса еще не получен:
- как "отсоединить" порожденный процесс, чтобы он продолжал выполняться независимо от родительского скрипта scala
Основная трудность заключается в том, что все классы, участвующие в порождении процесса, должны выполняться на JVM, и они неизбежно завершаются при выходе из JVM. Однако обходной путь заключается в косвенном достижении цели путем использования оболочки для "отсоединения" от вашего имени. Следующий скрипт scala, который запускает редактор gvim, работает должным образом:
val cmd = Список ( "Ла Скала", "-E", """import scala.sys.process._; "gvim".run; System.exit(0);""") val proc = cmd.run
Предполагается, что scala находится в PATH, и он (неизбежно) также оставляет выполнение родительского процесса JVM.