Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When using os.proc the PROMPT from bash "read -p PROMPT" is not written into stderr #380

Open
jk-1 opened this issue Mar 19, 2025 · 0 comments

Comments

@jk-1
Copy link

jk-1 commented Mar 19, 2025

I have following interactive test script echoStdOutErr.sh

#!/bin/bash

# This is used for testing how scala programs can launch external programs and
# handle / redirect their input and outputs

# Check if the mandatory first argument (exitValue) is provided
if [ -z "$1" ]; then
    echo "Error: exitValue is required as the first argument."
    echo "Usage: "
    echo " "
    echo "$0 exitValue <rowCount>"
    exit 1
fi

# Assign the first argument to exitValue
exitValue=$1

echo "stdOut => Starting: $0 $1 $2 ..."

# Check if rowCount was provided as a command-line argument
if [ -n "$2" ]; then
    rowCount=$2
else
    sleep 1
    # Prompt the user to enter rowCount interactively if not provided
    read -p "Enter the row count: " rowCount
fi

# Print rowCount to stdout
echo "stdOut => Row count entered: $rowCount"

# Print rowCount to stderr
>&2 echo "stdErr => Row count entered: $rowCount"

# Loop from 1 to rowCount
for ((i=1; i<=rowCount; i++))
do
    sleep 1
    # Check if the number is even
    if ((i % 2 == 0))
    then
        # Echo to stdout for even numbers
        echo "stdOut => Even number: $i"
    else
        # Echo to stderr for odd numbers
        >&2 echo "stdErr => Odd number: $i"
    fi
done
sleep 1
echo "stdOut => DONE: $rowCount echoes with exitValue $exitValue"
>&2 echo "stdErr => DONE: $rowCount echoes with exitValue $exitValue"

# Exit with the specified exitValue
exit $exitValue

and test run with input value 4 produces

echoStdOutErr.sh 123
stdOut => Starting: /home/jk/bin/echoStdOutErr.sh 123  ...
Enter the row count: 4
stdOut => Row count entered: 4
stdErr => Row count entered: 4
stdErr => Odd number: 1
stdOut => Even number: 2
stdErr => Odd number: 3
stdOut => Even number: 4
stdOut => DONE: 4 echoes with exitValue 123
stdErr => DONE: 4 echoes with exitValue 123

Here the PROMPT is logged to stderr as you see:

echoStdOutErr.sh 123 > out.log 2> err.log
4

cat err.log
Enter the row count: stdErr => Row count entered: 4
stdErr => Odd number: 1
stdErr => Odd number: 3
stdErr => DONE: 4 echoes with exitValue 123

Problem:
When I launch the script using os.proc(...).spawn(...) and try to log the stdout and stderr, I cannot get the PROMPT part logged anywhere.

Scala-cli test code stdOutErr.scala

//> using scala 2.13.0
//> using dep com.lihaoyi::os-lib:0.11.4

import java.text.SimpleDateFormat
import java.util.Date
import java.io.{BufferedReader, InputStreamReader, OutputStreamWriter, PrintWriter}
import scala.util.matching.Regex
import scala.util.Try

object StdOutErrEx {
  def main(args: Array[String]): Unit = {
    println(s"Running...")

    val echoCmdSeq: Seq[String] = Seq("echoStdOutErr.sh", "123")

    // Start the subprocess using os.proc with stdout and stderr as pipes
    val process = os.proc(echoCmdSeq).spawn(stdin = os.Pipe, stdout = os.Pipe, stderr = os.Pipe,
      env = Map("TERM" -> "xterm"), mergeErrIntoOut = false, propagateEnv = true)

    // Create BufferedReader for real-time streaming of stdout
    val stdoutReader = new BufferedReader(new InputStreamReader(process.stdout))
    val stderrReader = new BufferedReader(new InputStreamReader(process.stderr))
    val stdinWriter = new PrintWriter(new OutputStreamWriter(process.stdin))

    // Threads to print stdout and stderr in real time
    val stdoutThread = new Thread(() => {
      var line: String = stdoutReader.readLine()
      while (line != null) {
        println(s"STDOUT: $line")
        line = stdoutReader.readLine()
      }
    })

    val stderrThread = new Thread(() => {
      var line: String = stderrReader.readLine()
      while (line != null) {
        System.err.println(s"STDERR: $line")
        line = stderrReader.readLine()
      }
    })

    // Start both threads
    stdoutThread.start()
    stderrThread.start()

    // Write "4" to subprocess stdin
    stdinWriter.println("4")
    stdinWriter.flush()

    // Wait up to millis for the subprocess to terminate, by default waits indefinitely.
    // Returns true if the subprocess has terminated by the time this method returns.
    process.waitFor()

    stdinWriter.close() // Close stdin after writing to indicate EOF

    // Ensure threads finish
    stdoutThread.join()
    stderrThread.join()

    val processExitCode = process.exitCode()

    println(s"Process exited with code: $processExitCode")
  }
}

Running it produces:

scala-cli stdOutErr.scala 
Compiling project (Scala 2.13.0, JVM (17))
Compiled project (Scala 2.13.0, JVM (17))
Running...
STDOUT: stdOut => Starting: echoStdOutErr.sh 123  ...
STDOUT: stdOut => Row count entered: 4
STDERR: stdErr => Row count entered: 4
STDERR: stdErr => Odd number: 1
STDOUT: stdOut => Even number: 2
STDERR: stdErr => Odd number: 3
STDOUT: stdOut => Even number: 4
STDOUT: stdOut => DONE: 4 echoes with exitValue 123
STDERR: stdErr => DONE: 4 echoes with exitValue 123
Process exited with code: 123

scala-cli stdOutErr.scala > out.log 2> err.log

cat err.log 
STDERR: stdErr => Row count entered: 4
STDERR: stdErr => Odd number: 1
STDERR: stdErr => Odd number: 3
STDERR: stdErr => DONE: 4 echoes with exitValue 123

cat out.log
Running...
STDOUT: stdOut => Starting: /home/jk/bin/echoStdOutErr.sh 123  ...
STDOUT: stdOut => Row count entered: 4
STDOUT: stdOut => Even number: 2
STDOUT: stdOut => Even number: 4
STDOUT: stdOut => DONE: 4 echoes with exitValue 123
Process exited with code: 123

As you see PROMPT is not logged.

How can I get the PROMPT logged into stderr? Is this error in os.proc or am I using it incorrectly?

Thank you for your help and support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant