【问题标题】:Repeat Unix Command in Java在 Java 中重复 Unix 命令
【发布时间】:2010-11-05 15:04:59
【问题描述】:

有没有办法在 Java 中定期运行 Unix 命令(在我的例子中是 ps)?我写的循环:

while( this.check )
{
    try 
    {
            ProcessBuilder pb = new ProcessBuilder("ps");
            Process proc;

            System.out.println(" * * Running `ps` * * ");

            byte[] buffer;
            String input;

            proc = pb.start();
            BufferedInputStream osInput = 
                new BufferedInputStream(proc.getInputStream());

            //prints 0 every time after the first
            System.out.println(osInput.available());

            buffer = new byte[osInput.available()];
            osInput.read(buffer);
            input = new String(buffer);
            for( String line : input.split("\n"))
            {
                if( line.equals("") )
                    continue;
                this.handlePS(line);
            }

            proc.destroy();
            try 
            {
                Thread.sleep(10000);
            } 
            catch (InterruptedException ie) 
            {
                ie.printStackTrace();
            }
        } 
        catch (IOException ioe) 
        {
            ioe.printStackTrace();
        }
    }
}

不起作用。它第一次运行得很好,但此后每次输入流都有 0 个字节可用。我会尝试watch 命令,但这个 Solaris 盒子没有。我不能使用 cron 作业,因为我需要知道 PID 是否存在于 Java 应用程序中。有什么想法吗?

提前致谢。

编辑:无法使用 cron 作业

编辑:我正在制作一个新的相同类型 (PS) 的 Thread,所以我肯定每次都在制作一个新的 ProcessBuilder。

编辑:我把没有工作的循环放回去了,因为它引起了混乱。

【问题讨论】:

  • 放回循环以避免任何混乱

标签: java unix solaris inputstream


【解决方案1】:

我不确定循环在哪里,但每次循环都需要创建一个新的Proc 对象(因此也需要一个新的InputStream)。否则,您将始终查看第一次调用的结果。 ProcessBuilder 的 javadocs 表明您不需要每次都创建一个。

当您调用available() 时,也可能存在输入流尚未准备好的竞争条件。在打印结果之前,您应该确保输入流已达到 EOF(这将在 ps 中发生,但在 top 中不会发生)。

您也没有正确处理编码,尽管我不知道“ps”的输出是哪种编码(ASCII 之外)。由于“ps”可能是 ASCII,因此这是相当安全的,但可能不适用于其他命令(以及其他输入流)。

【讨论】:

  • 是的,我每次都在创建一个新进程。你读过代码吗?
  • 代码没有清晰的循环(编辑前),因为不清楚方法边界是什么
  • 竞争在 pb.start() 和 osInput.available() 之间。 sleep 命令不在这两个调用之间。正如其他人所指出的,应该在其间添加 Process.waitFor()。即便如此,当目标是获取整个流内容时,我倾向于不信任 available()。
  • 现在这很有帮助,谢谢。用它编辑你的答案,你就会被接受。
【解决方案2】:

除了 Kathy 的回答之外,您还应该在每次调用的单独线程中收集 stdout 和 stderr。否则进程会阻塞等待你读取这些数据。

更多详情请见this answer

编辑。您是否正在致电waitFor() 收集任何退出状态?我通常处理这个的方法是执行然后调用waitFor()。我认为destroy() 在这种情况下可能是多余的。

【讨论】:

  • 知道了。谢谢你的提示!实际上,我在启动该过程后立即调用了 waitFor()
【解决方案3】:

所以我认为问题在于您在 ps 执行结束之前检查输入流。尝试添加:

proc.waitFor()

在调用 osInput.available() 之前。

这是我的实现方式:

    TimerTask task = new TimerTask() {

        private void work() throws Exception {
            System.out.println("Now");
            ProcessBuilder pb = new ProcessBuilder("ps");
            Process p = pb.start();
            p.waitFor();
            BufferedReader reader
                = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                // Process line
                System.out.println(line);
            }
        }

        @Override
        public void run() {
            try {
                work();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

    Timer timer = new Timer();
    long period = 5000;
    timer.scheduleAtFixedRate(task, 0, period);

【讨论】:

    猜你喜欢
    • 2013-03-23
    • 1970-01-01
    • 1970-01-01
    • 2014-01-18
    • 1970-01-01
    • 2012-07-03
    • 2017-03-02
    • 2014-08-05
    • 2012-01-12
    相关资源
    最近更新 更多