Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Process

💡 お知らせ: このドキュメントはAIによって翻訳されています。表現に違和感がある場合は、原文(英語)を参照するか、翻訳にご協力ください。

Flix は、OS プロセスの起動と管理のためのライブラリエフェクト(library effect)として Process を提供しています。Process エフェクトにはデフォルトハンドラがあるため、main の中で明示的に runWithIO を呼び出す必要はありません。中心となるモジュールは Sys.Process です。

Process エフェクト

Process エフェクトは、プロセスの起動、その入出力ストリームへのアクセス、そして終了の待機をサポートしています。

pub eff Process {
    /// コマンド `cmd` を、引数 `args`、作業ディレクトリ `cwd`、環境変数 `env` で実行します。
    def execWithCwdAndEnv(cmd: String, args: List[String],
        cwd: Option[String], env: Map[String, String]):
        Result[IoError, ProcessHandle]

    /// プロセス `ph` の終了値を返します。
    def exitValue(ph: ProcessHandle): Result[IoError, Int32]

    /// プロセス `ph` が生存しているかどうかを返します。
    def isAlive(ph: ProcessHandle): Result[IoError, Bool]

    /// プロセス `ph` の PID を返します。
    def pid(ph: ProcessHandle): Result[IoError, Int64]

    /// プロセス `ph` の標準入力ストリームを返します。
    def stdin(ph: ProcessHandle): Result[IoError, StdIn]

    /// プロセス `ph` の標準出力ストリームを返します。
    def stdout(ph: ProcessHandle): Result[IoError, StdOut]

    /// プロセス `ph` の標準エラーストリームを返します。
    def stderr(ph: ProcessHandle): Result[IoError, StdErr]

    /// プロセス `ph` を停止します。
    def stop(ph: ProcessHandle): Result[IoError, Unit]

    /// プロセス `ph` の終了を待機し、その終了値を返します。
    def waitFor(ph: ProcessHandle): Result[IoError, Int32]

    /// プロセス `ph` の終了を最大 `time`(単位は `tUnit`)だけ待機します。
    /// プロセスが終了した場合は `true` を、タイムアウトした場合は `false` を返します。
    def waitForTimeout(ph: ProcessHandle, time: Int64, tUnit: TimeUnit):
        Result[IoError, Bool]
}

Process モジュール

Process モジュールは、Process エフェクトの上に構築された便利な関数を提供しています。

mod Process {
    /// コマンド `cmd` を引数 `args` で実行します。
    def exec(cmd: String, args: List[String]):
        Result[IoError, ProcessHandle] \ Process

    /// `cmd` を、引数 `args` と作業ディレクトリ `cwd` で実行します。
    def execWithCwd(cmd: String, args: List[String], cwd: Option[String]):
        Result[IoError, ProcessHandle] \ Process

    /// `cmd` を、引数 `args` と環境変数 `env` で実行します。
    def execWithEnv(cmd: String, args: List[String], env: Map[String, String]):
        Result[IoError, ProcessHandle] \ Process
}

コマンドの実行

OS プロセスを起動する最も簡単な方法は Process.exec を使うことです。この関数はコマンドと引数のリストを受け取り、Result[IoError, ProcessHandle] を返します。

use Sys.Process

def main(): Unit \ { Process, IO } =
    match Process.exec("java", "-version" :: Nil) {
        case Result.Ok(_)    => println("Process started successfully.")
        case Result.Err(err) => println("Unable to execute process: ${err}")
    }

プロセス出力の読み取り

プロセスを起動した後、Process.stdoutProcess.stderr でその出力ストリームにアクセスできます。返される StdOut 型と StdErr 型は Readable を実装しているため、そこからバイト列を読み取ることができます。

use Sys.Process

def main(): Unit \ { Process, IO } = region rc {
    match Process.exec("java", "-version" :: Nil) {
        case Result.Err(err) => println("exec failed: ${err}")
        case Result.Ok(ph)   =>
            match Process.stderr(ph) {
                case Result.Err(err) => println("stderr failed: ${err}")
                case Result.Ok(err)  =>
                    let buf = Array.repeat(rc, 1024, (0i8: Int8));
                    match Readable.read(buf, err) {
                        case Result.Err(e) => println("read failed: ${e}")
                        case Result.Ok(n)  => println("Read ${n} bytes from stderr.")
                    }
            }
    }
}

注意: java -version は標準出力ではなく標準エラーに書き込みます。

終了の待機

プロセスが終了するまでブロックするには Process.waitFor を使います。この関数は終了コードを Int32 として返します。

use Sys.Process

def main(): Unit \ { Process, IO } =
    match Process.exec("java", "-version" :: Nil) {
        case Result.Err(err) => println("exec failed: ${err}")
        case Result.Ok(ph)   =>
            match Process.waitFor(ph) {
                case Result.Err(err) => println("waitFor failed: ${err}")
                case Result.Ok(code) => println("Process exited with code: ${code}")
            }
    }

作業ディレクトリと環境変数

Process.execWithCwd は、特定の作業ディレクトリを指定してプロセスを起動します。Process.execWithEnv は、追加の環境変数を渡します。

use Sys.Process

def main(): Unit \ { Process, IO } =
    match Process.execWithCwd("java", "-version" :: Nil, Some("/tmp")) {
        case Result.Ok(_)    => println("execWithCwd succeeded.")
        case Result.Err(err) => println("execWithCwd failed: ${err}")
    };
    match Process.execWithEnv("java", "-version" :: Nil, Map#{"MY_VAR" => "hello"}) {
        case Result.Ok(_)    => println("execWithEnv succeeded.")
        case Result.Err(err) => println("execWithEnv failed: ${err}")
    }