与Kotlin进行交互式过程

huangapple go评论52阅读模式
英文:

Interactive process with Kotlin

问题

以下是您要的翻译内容:

I'm trying to interact with sh. This is the easiest case I want to resolve.
我正在尝试与 sh 交互。这是我想解决的最简单的情况。

The most easy is:
最简单的情况是:

typealias ExitStatus = Int

fun executeIO(cmd: List<String>): ExitStatus =
    ProcessBuilder(cmd).inheritIO().start().waitFor()

But the Kotlin code doesn't have any control when the sh are executing.
但是 Kotlin 代码在 sh 执行时没有任何控制。

When you know how many times you want to write
当您知道要写多少次时:

fun executeNTimes(cmd: List<String>, times: Int) = runBlocking {
    val process = ProcessBuilder(cmd)
        .start()

    launch { process.errorStream.bufferedReader().useLines { seq -> seq.toList().forEach { println("stderr: $it") } } }
    launch { process.inputStream.bufferedReader().useLines { seq -> seq.toList().forEach { println("stdout: $it") } } }

    OutputStreamWriter(process.outputStream, "UTF-8").use { w ->
        repeat(times) {
            readln().let { println("input: $it"); w.write(it) }
            w.appendLine()
            w.flush()
        }
    }
    process.waitFor()
}

But that is not interactive!
但这并不是交互式的!
> cmd = sh and times = 2:
> cmd = sh,times = 2:

echo exit on stdout
input: echo exit on stdout
echo exit on stderr 1>&2 
input: echo exit on stderr 1>&2
stderr: exit on stderr
stdout: exit on stdout

Is not interactive because needs to close the buffer for starting to work.
这不是交互式的,因为需要关闭缓冲区才能开始工作。

My expectation for an interactive process is the next one:
我的期望是进行交互式处理:

input: echo exit on stdout
stdout: exit on stdout
input: echo exit on stderr 1>&2
stderr: exit on stderr
input: exit

How can I do that?
我该如何实现这一点?

英文:

I'm trying to interact with sh. This is the easiest case I want to resolve.

The most easy is:

typealias ExitStatus = Int

fun executeIO(cmd: List<String>): ExitStatus =
    ProcessBuilder(cmd).inheritIO().start().waitFor()

But the Kotlin code doesn't have any control when the sh are executing.

When you know how many times you want to write

fun executeNTimes(cmd: List<String>, times: Int) = runBlocking {
    val process = ProcessBuilder(cmd)
        .start()

    launch { process.errorStream.bufferedReader().useLines { seq -> seq.toList().forEach { println("stderr: $it") } } }
    launch { process.inputStream.bufferedReader().useLines { seq -> seq.toList().forEach { println("stdout: $it") } } }

    OutputStreamWriter(process.outputStream, "UTF-8").use { w ->
        repeat(times) {
            readln().let { println("input: $it"); w.write(it) }
            w.appendLine()
            w.flush()
        }
    }
    process.waitFor()
}

But that is not interactive!
> cmd = sh and times = 2:

echo exit on stdout
input: echo exit on stdout
echo exit on stderr 1>&2 
input: echo exit on stderr 1>&2
stderr: exit on stderr
stdout: exit on stdout

Is not interactive because needs to close the buffer for starting to work.

My expectation for interactive process is the next one:

input: echo exit on stdout
stdout: exit on stdout
input: echo exit on stderr 1>&2
stderr: exit on stderr
input: exit

How I can do that?

答案1

得分: 0

以下是您要的翻译部分:

"After read:

The code has:

fun executeExpect() {
    val process = ProcessBuilder(listOf("sh")).start()
    val expect = ExpectBuilder()
        .withInputs(process.inputStream, process.errorStream)
        .withOutput(process.outputStream)
        .build()

    fun send(str: String) {
        expect.sendLine(str)
        println("input: $str")
    }
    "echo exit on stdout".let(::send)
    expect.expect(regexp("\n$")).before.let { println("stdout: $it") }
    "echo exit on stderr 1>&2".let(::send)
    expect.expectIn(1, regexp("\n$")).before.let { println("stderr: $it") }
    "exit".let(::send)
    expect.expect(eof());
    process.waitFor()
    expect.close()
}

And now the output is:

input: echo exit on stdout
stdout: exit on stdout
input: echo exit on stderr 1>&2
stderr: exit on stderr
input: exit
```"

<details>
<summary>英文:</summary>

After read:
- https://github.com/agavrilov76/ExpectIt
  - https://github.com/agavrilov76/ExpectIt/blob/master/expectit-core/src/test/java/net/sf/expectit/ProcessExample.java
- https://en.wikipedia.org/wiki/Expect

The code has:
```kotlin
fun executeExpect() {
    val process = ProcessBuilder(listOf(&quot;sh&quot;)).start()
    val expect = ExpectBuilder()
        .withInputs(process.inputStream, process.errorStream)
        .withOutput(process.outputStream)
        .build()

    fun send(str: String) {
        expect.sendLine(str)
        println(&quot;input: $str&quot;)
    }
    &quot;echo exit on stdout&quot;.let(::send)
    expect.expect(regexp(&quot;\n$&quot;)).before.let { println(&quot;stdout: $it&quot;) }
    &quot;echo exit on stderr 1&gt;&amp;2&quot;.let(::send)
    expect.expectIn(1, regexp(&quot;\n$&quot;)).before.let { println(&quot;stderr: $it&quot;) }
    &quot;exit&quot;.let(::send)
    expect.expect(eof());
    process.waitFor()
    expect.close()
}

And now the output is:

input: echo exit on stdout
stdout: exit on stdout
input: echo exit on stderr 1&gt;&amp;2
stderr: exit on stderr
input: exit

huangapple
  • 本文由 发表于 2023年3月15日 18:16:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/75743325.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定