Execute a shell command using processBuilder and i

2019-04-10 05:22发布

问题:

I'm trying to create a program allowing me to execute a command through a terminal (which is OmxPlayer for raspberry pi if you want to know) with arguments, but i'd want to be able to interact with it once I have launched the command.

For example i'd want to do : omxplayer -win x1 y1 x2 y2 and then be able to press "p" to pause the video/audio media

I already have something that can launch the omxplayer with arguments (actually it's "ls" but it should work exactly the same way) but I don't understand how to interact with the terminal once i've launched the command through the processBuilder.

Here's what i've got at the moment :

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class Main1 {

    public static void main(String a[]){

        InputStream is = null;
        ByteArrayOutputStream baos = null;
        List<String> commands = new ArrayList<String>();
        commands.add("ls");
        commands.add("-l");
        commands.add("/");
        ProcessBuilder pb = new ProcessBuilder(commands);
        try {
            Process prs = pb.start();
            is = prs.getInputStream();
            byte[] b = new byte[1024];
            int size = 0;
            baos = new ByteArrayOutputStream();
            while((size = is.read(b)) != -1){
                baos.write(b, 0, size);
            }
            System.out.println(new String(baos.toByteArray()));
        } 
        catch (IOException e) 
        {
            e.printStackTrace();
        } 
        finally
        {
            try {
                if(is != null) is.close();
                if(baos != null) baos.close();
            } catch (Exception ex){}
        }
    }
}

回答1:

"(actually it's "ls" but it should work exactly the same way)"

No, it is not. Because the 'ls' process returns immediately after its call. Your omixplayer at the other hand is interactive and will accept commands at runtime.

What you have to do:

  • create a class which implements Runnable and let this class read from the prs.getInputStream(). You will need this because the .read() will block and wait for new data to read.

  • get the OutputStream of the Process object (prs.getOutputStream()). Everything you write to the OutputStream will be read from your omixplayer. Don't forget to flush the OutputStream and every command needs an "\n" at the end to be executed.

Like that:

public class TestMain {
    public static void main(String a[]) throws InterruptedException {

        List<String> commands = new ArrayList<String>();
        commands.add("telnet");
        commands.add("www.google.com");
        commands.add("80");
        ProcessBuilder pb = new ProcessBuilder(commands);
        pb.redirectErrorStream(true);
        try {

            Process prs = pb.start();
            Thread inThread = new Thread(new In(prs.getInputStream()));
            inThread.start();
            Thread.sleep(2000);
            OutputStream writeTo = prs.getOutputStream();
            writeTo.write("oops\n".getBytes());
            writeTo.flush();
            writeTo.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class In implements Runnable {
    private InputStream is;

    public In(InputStream is) {
        this.is = is;
    }

    @Override
    public void run() {
        byte[] b = new byte[1024];
        int size = 0;
        try {
            while ((size = is.read(b)) != -1) {
                System.err.println(new String(b));
            }
            is.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

P.S.: Keep in mind this example is quick an dirty.