scala - 是什么导致这个 Scala 程序在后台运行时由于 tty 输出而挂起?

标签 scala shell tty

假设我们有以下 Scala (2.12)。它正在使用 ProcessBuilder执行一组非常简单的命令( sleep ,后跟 echo )。该程序还捕获 stdout 和 stderr,并将所有行(带有相应的前缀)打印到 Scala 进程本身的 stdout 或 stderr。

import scala.sys.process._
import scala.language.postfixOps

object BackgroundProcessRedirect {
  def main(args: Array[String]) = {
    val output = "sleep 5" #&& s"echo myoutput" lineStream_! ProcessLogger(line => System.err.println(s"stderr: $line"))
    output.foreach(line => System.out.println(s"stdout: $line"))
  }
}

在 OS X 上执行时,可以在 zsh 中执行5.6.2 或 GNU bash 4.4.23(1),除非附加了 stdin,否则进程会因 tty 输出而挂起。尽管命令( sleepecho )都不应该尝试从 stdin 读取,但还是会发生这种情况。

# first, compile
scalac BackgroundProcessRedirect.scala

# now, run as a background process, redirecting stdout and stderr to files
scala BackgroundProcessRedirect >/tmp/scala.out 2>/tmp/scala.err &

# after 5 seconds, the process is suspended, as in the following jobs output
[1]  + <PID> suspended (tty output)  scala BackgroundProcessRedirect > /tmp/scala.out 2> /tmp/scala.err

# now, foreground the process; it will complete immediately
fg
# the output file contents are as expected
cat /tmp/scala.out
stdout: myoutput

# run the same thing again, but this time redirect stdin from /dev/null
scala BackgroundProcessRedirect </dev/null >/tmp/scala.out 2>/tmp/scala.err &

# now, the process completes normally after 5 seconds (not suspended), and the file contents are as expected
cat /tmp/scala.out
stdout: myoutput

如果程序一开始只是在前台运行,那么它也不会被挂起。有什么想法可能导致此问题吗?

正在运行stty -tostop在启动 scala 的任一终端中,或在调用这些相同命令的新脚本文件中,然后由 scala 调用,对此行为没有影响。

最佳答案

This happens despite the fact that neither command (sleep nor echo) should be trying to read from stdin

请注意,该消息显示“tty 输出”,而不是“tty 输入”。所以它提示的是进程产生输出,而不是从标准输入读取。这很奇怪,有两个原因:

  1. 定期输出到 stdout 或 stderr 通常不会导致后台进程暂停
  2. 无论如何,您都会重定向 stdout 和 stderr,因此即使您的终端设置为在输出时暂停,在这种情况下也不应该发生这种情况。

输出暂停通常仅在进程使用 tty 功能而不仅仅是写入标准流时才会发生(例如写入屏幕上的特定位置或通常需要诅咒或类似功能的任何内容)。

你的程序没有这样做,但显然scala二进制确实如此。至少我可以在尝试使用 scala className& 运行任何 Scala 程序时重现您的问题。 ,但是当我使用 java -cp /usr/share/scala/lib/scala-library.jar:. className& 时它就消失了相反。

所以我的结论是scala以破坏后台进程的方式与 tty 交互,解决方法是使用 java相反。

<小时/>

1 查看 /usr/bin/scala 后,看起来它正在调用 stty保存和恢复终端设置。显然,如果进程在后台运行(因此未正确连接到 tty),则该方法不起作用,这就是进程被挂起的原因。

关于scala - 是什么导致这个 Scala 程序在后台运行时由于 tty 输出而挂起?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55504538/

相关文章:

c - 切换其他人写入您的终端的权限的过程 [Unix] [C]

Linux 去除串口多余字符

scala - 如何允许在 Spark 2 的数据框中接受无值?

linux - 基于shell中正则表达式的颜色突出显示输出

linux - 如何让 2 个变量具有 2 个不同的序列 - Bash Linux

LINUX Shell脚本将行转换为多列

perl - 判断 Perl 脚本的 STDOUT 是否被重定向

scala - jvm 选项未传递给 fork 进程

scala - '结果的长度应为 3' : How does the ScalaTest DSL work?

json - 如何在 Play Json 中使用 Joda DateTime