在 Java 中重复 Unix 命令

发布于 2024-07-25 04:47:10 字数 1521 浏览 14 评论 0原文

有没有办法在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。

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

Is there a way to periodically run a Unix command (ps in my case) in Java? The loop I wrote:

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();
        }
    }
}

doesn't work. It runs perfectly fine the first time, but there are 0 bytes available from the input stream every time after that. I'd try the watch command, but this Solaris box doesn't have that. I can't use a cron job since I need to know if the PID is there in the Java Application. Any ideas?

Thanks in advance.

EDIT: cannot use cron job

EDIT: I'm making a new Thread of the same type (PS) after it concludes, so I am definitely making a new ProcessBuilder every time.

EDIT: I put the loop that didnt work back in since it caused confusion.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

隐诗 2024-08-01 04:47:10

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

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

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

I'm not certain where the loop is, but you will need to create a new Proc object (and thus a new InputStream) each time through the loop. Otherwise you will always be looking at the result to the first call. The javadocs for ProcessBuilder indicate that you do not need to create one of those each time.

There may also be a race condition where the input stream is not yet ready when you callk available(). You should look at making certain that the input stream has reached EOF (which will happen with ps, although not with, say, top) before printing the results.

You are also not handling encoding properly, although I don't know what kind of encoding the output of "ps" is (outside of ASCII). Since "ps" is probably ASCII this is reasonably safe, but may not be for other commands (and for other input streams).

灵芸 2024-08-01 04:47:10

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

有关更多详细信息,请参阅此答案

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

In addition to Kathy's answer, you should also gather stdout and stderr in separate threads for each invocation. Otherwise the process will block waiting for you to read this data.

See this answer for more details.

EDIT. Are you calling waitFor() to gather any exit status ? The way I would normally approach this is to execute and then call waitFor(). I think destroy() may be redundant in this context.

烦人精 2024-08-01 04:47:10

所以我认为问题在于您在 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);

So I think that the problem is that you are checking the input stream before the end of ps execution. Try adding:

proc.waitFor()

before calling osInput.available().

Here is how I would have implemented it:

    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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文