Hoe een Linux Shell-opdracht uit Java

Ik probeer een aantal Linux-opdrachten uit Java uit te voeren met behulp van omleiding (& GT; & amp;) en pijpen (|). Hoe kan Java zich aanroepen cshof bash-opdrachten?

Ik heb geprobeerd dit te gebruiken:

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

Maar het is niet compatibel met omleidingen of leidingen.


Antwoord 1, Autoriteit 100%

Exec voert geen opdracht uit in uw shell

Probeer

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

in plaats daarvan.

Bewerken ::
Ik heb geen csh op mijn systeem, dus ik heb in plaats daarvan bash gebruikt. Het volgende werkte voor mij

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

Antwoord 2, Autoriteit 31%

Gebruik ProcessBuilder om opdrachten en argumenten in plaats van spaties te scheiden. Dit zou moeten werken, ongeacht de gebruikte schaal:

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

Antwoord 3, Autoriteit 15%

Gebouw op het voorbeeld van @ Tim om een ​​zelfstandige methode te maken:

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

(Het testvoorbeeld is een opdracht die alle bestanden in een map en zijn submappen recursief, in chronologische volgorde weergeeft.)

Trouwens, als iemand me kan vertellen waarom ik vier en acht backslashes nodig heb, in plaats van twee en vier, kan ik iets leren. Er is nog een niveau van niet-ontsnappen dat gebeurt dan wat ik tel.

Bewerken: Ik heb net dezelfde code op Linux geprobeerd, en daar blijkt dat ik de helft minder backslashes nodig heb in het testcommando! (Dat wil zeggen: het verwachte aantal van twee en vier.) Nu is het niet langer alleen maar raar, het is een draagbaarheidsprobleem.

Other episodes