Skip to content

dart.io.Process.runのworkingDirectoryとrunInShellの挙動

環境

windows 10

Process class とは

この class を利用することによって、cui の操作を dart で記述することができます。


import 'dart:io';

void main() {
    final process = await Process.run(
        // windows の コマンドプロンプト.
    // 引数を何も指定しない場合 current directory 内の一覧を表示する.
    'dir',
        [], // dir コマンドの引数が入る. 今回引数が無いので空の配列.
        runInShell: true,
    );
    print(process.stdout);
    print(process.stderr);
    print(process.exitCode);
}

cui を走らせた結果がそれぞれ、stdout, stderr, exitCode, 内に格納されます。

git bash をインストールしているなら git の操作もできます。 さらに、git を操作するための package が既にあるので、私はそれを使っています。 中身を見ると、git の command を実行する部分は、この Process class 利用し、Process.start -> runGit -> runCommand という感じで wrap されていて、package 利用者は runCommand を呼び出して、git command を実行します。 https://pub.dev/packages/git runGit https://github.com/kevmoo/git/blob/master/lib/src/top_level.dart runCommand https://github.com/kevmoo/git/blob/master/lib/src/git_dir.dart

本題

Process.run や Process.start で cui を実行できるのですが、その際に設定する引数である、workingDirectory や runInShell に関する挙動に関して、説明を読んでも意図がはっきり理解できず、実際にいろいろ試して把握できた内容の記録になります。 https://api.dart.dev/stable/3.0.4/dart-io/Process-class.html https://api.dart.dev/stable/3.0.4/dart-io/Process/run.html https://api.dart.dev/stable/3.0.4/dart-io/Process/start.html

workingDirectory

cui を実行する際、current directory は重要な概念ですが、workingDirectory はそれと同じような働きを担います。 dart で cui を実行する際、cd などを使って current directory を移動することができません。 https://stackoverflow.com/questions/73151520/cant-use-cd-command-in-dart-cli-application なので、file などの出力が current directory に限定されている cui の操作を実行する場合、本来なら cd で移動し current directory にしたい directory を workingDirectory に設定します。


import 'dart:io';

void main() async {
    final process = await Process.run(
        'dir',
        [],
        runInShell: true,
    workingDirectory: 'sub_directory_a'
    );
    print(process.stdout);
    print(process.stderr);
    print(process.exitCode);
}

workingDirectory: で 'sub_directory_a' を指定したため、sub_directory_a folder 内の一覧が表示されます。

runInShell

Process class に限らず dart:io 内の api は、実行する環境(windows, osx, linux, など)で挙動の詳細が異なる場合あります。

コマンドプロンプト

「%WINDIR%\system32\cmd.exe が使用される」ということで、これはつまりコマンドプロンプトを実行するということになります。 上記の例で使用している dir は コマンドプロンプトのコマンドなので runInShell: true に設定しています。 false にした場合、エラーになります。 これは、windows 環境で Process class の簡単な動きを実際に確かめたいときにおすすめです。コマンドプロンプトは windows なら初めからインストールされています。

PowerShell

Process の動きを確かめるときに、はじめは powershell で試したのですが、期待通りの結果を得られず、本当によくわかりませんでした。 vscode の terminal では普通に動くのに、Process だと runInShell が true or false にかかわらず動なかったのでとてもストレスになりました。予定調和な挙動をしないので、個人的にお勧めしません。 PowerShell は PowerShell 専用の terminal じゃないと動かないのかもしれません。 もしかしたら、powershell の PATH を通せば Process でも操作できるようになるかもしれません。 とりあえず、そのままの状態では Process で操作はできませんでした。

PATH を通せば true or false にかかわらず動く?

PATH を通してある git の場合 true でも flase でも動きました。


import 'dart:io';

void main() async {
    final process = await Process.run(
        'git',
        ['branch'],
    runInShell: true,
    // runInShell: false,
    );
    print(process.stdout);
    print(process.stderr);
    print(process.exitCode);
}

おわりに

windows 10 環境における、自分の中で試した範囲での記録になっています。さらにわかったことなどがあれば、追記していくかもしれません。