【问题标题】:Bash Input and Output RedirectsBash 输入和输出重定向
【发布时间】:2014-02-21 13:30:57
【问题描述】:

我有一个在 Mac OS X 上使用 Bash 脚本运行的 Java 程序。我有两个文件 - 一个允许我将命令通过管道传输到程序中的 FIFO,以及一个输出日志文件。

Bash 脚本由以下代码组成:

#!/bin/bash
java -jar file.jar <./run/command-fifo >>./run/server.log 2>&1 &
echo $! >| ./run/server.pid

老实说,我不记得为什么我在第三行中使用了&gt;|(我只知道它有效)。在 java 行中,第一个 &lt; 将 fifo 文件重定向到标准输入。 &gt;&gt; 应该将标准输出重定向到文件,2&gt;&amp;1 也应该将标准错误重定向到它。然后它在后台运行。

问题是没有任何东西写入 server.log 文件。读取 command-fifo 文件,但不写入日志。该程序正在写入标准输出(如果我自己运行它,它工作正常)。

我也按照this question 中的建议尝试了script,但也没有用:

script -q /dev/null java -Xmx4G -Xms4G -jar current.jar --nogui <./run/command-fifo >>./run/server.log 2>&1 &

任何人有想法让它正确写入日志?

跟进:我应该多解释一下软件是如何工作的,这样解释才有意义。这里有三个部分在起作用:

  1. launchd 用于通过调用启动器脚本在启动时启动程序的 plist
  2. 处理终止信号并等待 java 进程的 pid 的启动器脚本
  3. 由启动器脚本调用的启动脚本,用于启动程序并保存其 pid

上面给出的脚本是启动脚本。这将启动 java 进程,将其 pid 回显到文件,然后返回。启动器脚本(此处未给出)然后等待 pid 在终止之前退出。如果它终止,launchd 会自动重新启动启动器脚本。

Launchd 有一个特性,可以为它启动的文件设置标准输出路径。本质上,它将启动器脚本的标准输出重定向到给定的文件。

我这样做了,你瞧,它有效。通过将启动脚本行更改为以下内容:

java -jar file.jar <>./run/command-fifo &

它允许 launchd 捕获标准输出并将其写入文件。这是一个有点不同的解决方案,但它确实有效。这很奇怪,因为启动器脚本在技术上没有任何输出,因为 java 进程在后台,但是不管它如何工作,它确实以某种方式工作。

当然,我更喜欢将文件的标准输出显式重定向到一个文件中(在其他脚本中,可能存在多个文件,我需要将它们分开)。我仍然会尝试并尝试找到解决方案。

【问题讨论】:

  • 我不是 java 专家,但我敢打赌你的 java 程序只是在缓冲输出(可能会在输出大小达到 8K 或 64K 字节时写入)。同时,&gt;| 重定向运算符的意思是“写入文件,即使它存在 并且 我也已经完成了set -o noclobber,因此您通常会拒绝重定向并显示文件存在的错误”。更令人难忘的是,管道的意思是:“我是认真的!”

标签: bash redirect background-process


【解决方案1】:

我认为@torek 关于缓冲的评论可能是正确的。您可以使用stdbuf utility 强制您的java 进程对其输出进行行缓冲:

#!/bin/bash
stdbuf -oL java -jar file.jar <./run/command-fifo >>./run/server.log 2>&1 &
echo $! >| ./run/server.pid

关于&gt;| 运算符,@torek 也是正确的。 Here is the bash manual entry.

【讨论】:

  • 谢谢。不幸的是,stdbuf(和看起来相似的unbuffer)没有安装在 Mac OS X 上,也没有正式可用。我正在寻找安装它们的方法,但这可能是不可能的。我确实尝试过script -q /dev/null java -Xmx4G -Xms4G -jar current.jar --nogui &lt;./run/command-fifo &gt;&gt;./run/server.log 2&gt;&amp;1 &amp;,但这也不起作用。
  • @JustinMrkva - 抱歉,我不确定这里发生了什么。我可以让script -q 在这个例子中工作:for ((i=0;;i++)); do echo $i; sleep 0.001; done | grep . &gt;&gt; server.log - 这里grep 缓冲它到文件的重定向 - 你可以通过tail -fing 文件看到这一点。但是如果你这样做for ((i=0;;i++)); do echo $i; sleep 0.001; done | script -q /dev/null grep . &gt;&gt; server.log,那么你会看到文件不断更新。
  • 见上面的后续。我让它以不同的方式工作。我认为java程序本身可能与奇怪的行为有关,但我不知道。我运行了你的脚本,我看到的结果与你的结果一致。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-14
  • 1970-01-01
  • 2012-04-04
  • 2013-03-30
  • 2011-07-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多