Cách gọi lệnh shell Linux từ Java


93

Tôi đang cố gắng thực thi một số lệnh Linux từ Java bằng cách sử dụng chuyển hướng (> &) và đường ống (|). Java có thể gọi cshhoặc bashlệnh như thế nào?

Tôi đã cố gắng sử dụng cái này:

Process p = Runtime.getRuntime().exec("shell command");

Nhưng nó không tương thích với chuyển hướng hoặc đường ống.


2
catcshkhông liên quan gì đến nhau.
Bombe 11/09/09

4
Tôi có thể hiểu câu hỏi đối với các lệnh khác, nhưng đối với mèo: tại sao bạn không đọc trong tệp?
Atmocreations 11/09/09

8
Mọi người đều mắc phải sai lầm này lần đầu tiên - Javascript () của Java không sử dụng shell của hệ thống cơ bản để thực thi lệnh (như kts đã chỉ ra). Chuyển hướng và đường ống là các tính năng của một trình bao thực và không có sẵn từ tệp thi hành () của Java.
SteveD 11/09/09

stevendick: Cảm ơn bạn rất nhiều, tôi đã gặp sự cố do chuyển hướng và đường ống!
Narek 13/09/09

System.exit (0) không nằm trong kiểm tra có điều kiện nếu quá trình được thực hiện, vì vậy nó sẽ luôn thoát mà không có lỗi xuất ra. Không bao giờ viết điều kiện không có dấu ngoặc nhọn, để tránh chính xác loại sai lầm này.

Câu trả lời:


96

execute không thực hiện một lệnh trong trình bao của bạn

thử

Process p = Runtime.getRuntime().exec(new String[]{"csh","-c","cat /home/narek/pk.txt"});

thay thế.

CHỈNH SỬA :: Tôi không có csh trên hệ thống của mình vì vậy tôi đã sử dụng bash để thay thế. Những điều sau đây đã làm việc cho tôi

Process p = Runtime.getRuntime().exec(new String[]{"bash","-c","ls /home/XXX"});

@Narek. Xin lỗi vì điều đó. Tôi cố định nó bằng cách loại bỏ thêm \" 's Rõ ràng họ không cần tôi không có csh trên hệ thống của tôi, nhưng nó hoạt động với bash..
KitsuneYMG

3
Như những người khác đã đề cập, điều này nên được làm ướt độc lập hơn bạn có csh hoặc bash, phải không?
Narek 17/09/09

@Narek. Nó nên, nhưng tôi không biết cách csh xử lý các đối số.
KitsuneYMG 17/09/09

1
Cảm ơn bạn. Điều này đã hiệu quả. Trên thực tế, tôi đã sử dụng "sh" thay vì "csh".
Farshid

5
Cảnh báo: giải pháp này rất có thể sẽ gặp phải sự cố điển hình là nó bị treo vì bạn không đọc các luồng lỗi và đầu ra của nó. Ví dụ: stackoverflow.com/questions/8595748/java-runtime-exec
Evgeni Sergeev

32

Sử dụng ProcessBuilder để tách các lệnh và đối số thay vì khoảng trắng. Điều này sẽ hoạt động bất kể trình bao được sử dụng:

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class Test {

    public static void main(final String[] args) throws IOException, InterruptedException {
        //Build command 
        List<String> commands = new ArrayList<String>();
        commands.add("/bin/cat");
        //Add arguments
        commands.add("/home/narek/pk.txt");
        System.out.println(commands);

        //Run macro on target
        ProcessBuilder pb = new ProcessBuilder(commands);
        pb.directory(new File("/home/narek"));
        pb.redirectErrorStream(true);
        Process process = pb.start();

        //Read output
        StringBuilder out = new StringBuilder();
        BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String line = null, previous = null;
        while ((line = br.readLine()) != null)
            if (!line.equals(previous)) {
                previous = line;
                out.append(line).append('\n');
                System.out.println(line);
            }

        //Check result
        if (process.waitFor() == 0) {
            System.out.println("Success!");
            System.exit(0);
        }

        //Abnormal termination: Log command parameters and output and throw ExecutionException
        System.err.println(commands);
        System.err.println(out.toString());
        System.exit(1);
    }
}

Ngay cả sau java.util. *; được nhập đúng cách Tôi không thể lấy ví dụ trên để chạy.
Steve K,

@Stephan Tôi đã cập nhật mã ví dụ ở trên để xóa các câu lệnh ghi nhật ký và các biến được khai báo bên ngoài mã đã dán, và bây giờ nó sẽ biên dịch và chạy. Hãy thử và cho tôi biết nó hoạt động như thế nào.
Tim vào

15

Dựa trên ví dụ của @ Tim để tạo ra một phương pháp khép kín:

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class Shell {

    /** Returns null if it failed for some reason.
     */
    public static ArrayList<String> command(final String cmdline,
    final String directory) {
        try {
            Process process = 
                new ProcessBuilder(new String[] {"bash", "-c", cmdline})
                    .redirectErrorStream(true)
                    .directory(new File(directory))
                    .start();

            ArrayList<String> output = new ArrayList<String>();
            BufferedReader br = new BufferedReader(
                new InputStreamReader(process.getInputStream()));
            String line = null;
            while ( (line = br.readLine()) != null )
                output.add(line);

            //There should really be a timeout here.
            if (0 != process.waitFor())
                return null;

            return output;

        } catch (Exception e) {
            //Warning: doing this is no good in high quality applications.
            //Instead, present appropriate error messages to the user.
            //But it's perfectly fine for prototyping.

            return null;
        }
    }

    public static void main(String[] args) {
        test("which bash");

        test("find . -type f -printf '%T@\\\\t%p\\\\n' "
            + "| sort -n | cut -f 2- | "
            + "sed -e 's/ /\\\\\\\\ /g' | xargs ls -halt");

    }

    static void test(String cmdline) {
        ArrayList<String> output = command(cmdline, ".");
        if (null == output)
            System.out.println("\n\n\t\tCOMMAND FAILED: " + cmdline);
        else
            for (String line : output)
                System.out.println(line);

    }
}

(Ví dụ kiểm tra là một lệnh liệt kê tất cả các tệp trong một thư mục và các thư mục con của nó, một cách đệ quy, theo thứ tự thời gian .)

Nhân tiện, nếu ai đó có thể cho tôi biết tại sao tôi cần bốn và tám dấu gạch chéo ngược ở đó, thay vì hai và bốn, tôi có thể học được điều gì đó. Có một mức độ không thoát nữa đang xảy ra hơn những gì tôi đang kể.

Chỉnh sửa: Chỉ cần thử cùng một mã này trên Linux, và hóa ra là tôi cần một nửa số dấu gạch chéo ngược trong lệnh thử nghiệm! (Đó là: con số dự kiến ​​là hai và bốn.) Giờ đây, nó không còn kỳ lạ nữa, đó là một vấn đề về tính di động.


Bạn nên đặt câu hỏi của mình dưới dạng câu hỏi StackOverflow mới, không phải là một phần trong câu trả lời của bạn.
vog

Hoạt động với hai và bốn trên OSX / Oracle java8. Dường như có một vấn đề với môi trường java ban đầu của bạn (mà bạn không đề cập đến bản chất của)
TheMadsen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.