Java'dan bir Linux kabuk komutu nasıl çağrılır


93

Yeniden yönlendirme (> &) ve borular (|) kullanarak Java'dan bazı Linux komutlarını çalıştırmaya çalışıyorum. Java nasıl çalıştırabilir cshveya bashkomut verebilir ?

Bunu kullanmayı denedim:

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

Ancak yeniden yönlendirmeler veya borularla uyumlu değildir.


2
catve cshbirbirinizle hiçbir ilgisi yok.
Bombe

4
diğer komutlar için soruyu anlayabiliyorum, ama kedi için: neden dosyada sadece okumuyorsun?
Atmocreations

8
Herkes bunu ilk seferde yanlış anlar - Java'nın exec () işlevi, komutu yürütmek için temeldeki sistemin kabuğunu kullanmaz (kts'nin işaret ettiği gibi). Yönlendirme ve borulama gerçek bir kabuğun özellikleridir ve Java'nın exec () 'de mevcut değildir.
SteveD

stevendick: Çok teşekkür ederim, yönlendirme ve borulama nedeniyle problemler alıyordum!
Narek

System.exit (0), işlem yapılırsa koşullu kontrol içinde değildir, bu nedenle her zaman hata vermeden çıkar. Tam olarak bu tür bir hatadan kaçınmak için, koşul ifadelerini asla parantez olmadan yazmayın.

Yanıtlar:


97

exec kabuğunuzda bir komut yürütmez

Deneyin

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

yerine.

DÜZENLEME :: Sistemimde csh yok, bu yüzden onun yerine bash kullandım. Aşağıdakiler benim için çalıştı

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

@Narek. Bunun için üzgünüm. Görünüşe göre gerekli olmayan fazlalıkları kaldırarak düzelttim. Sistemimde csh yok, ancak bash ile çalışıyor.
KitsuneYMG

3
Başkalarının da belirttiği gibi, ister csh ister bash olsun, bu bağımsız olmalıdır, değil mi?
Narek

@Narek. Olmalı, ama csh'nin argümanları nasıl ele aldığını bilmiyorum.
KitsuneYMG

1
Teşekkür ederim. Bu işe yaradı. Aslında "csh" yerine "sh" kullandım.
Farshid

5
Uyarı: Bu çözüm, büyük olasılıkla tipik bir asılı sorunla karşılaşacaktır çünkü çıktılarını ve hata akışlarını okumadınız. Örneğin: stackoverflow.com/questions/8595748/java-runtime-exec
Evgeni Sergeev

32

Boşluklar yerine komutları ve bağımsız değişkenleri ayırmak için ProcessBuilder'ı kullanın. Bu, kullanılan kabuktan bağımsız olarak çalışmalıdır:

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

Java.util. *; düzgün bir şekilde içe aktarıldı, çalıştırmak için yukarıdaki örnek alamıyorum.
Steve K

@Stephan Yapıştırılan kodun dışında bildirilen günlük ifadelerini ve değişkenleri kaldırmak için yukarıdaki örnek kodu güncelledim ve şimdi derleyip çalıştırması gerekiyor. Nasıl çalıştığını bana bildirmekten çekinmeyin.
Tim

15

Kendi kendine yeten bir yöntem yapmak için @ Tim'in örneğine dayanarak:

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

    }
}

(Test örneği, bir dizindeki tüm dosyaları ve alt dizinlerini kronolojik sırada yinelemeli olarak listeleyen bir komuttur .)

Bu arada, biri bana neden orada iki ve dört yerine dört ve sekiz ters eğik çizgiye ihtiyacım olduğunu söylerse, bir şeyler öğrenebilirim. Saydığımdan bir kaçış geri dönüş seviyesi daha var.

Düzenleme: Aynı kodu Linux'ta da denedim ve orada test komutunda yarısı kadar ters eğik çizgiye ihtiyacım olduğu ortaya çıktı! (Yani: beklenen iki ve dört sayısı.) Artık bu sadece tuhaf değil, taşınabilirlik sorunu.


Sorunuzu cevabınızın bir parçası olarak değil, yeni StackOverflow sorusu olarak sormalısınız.
vog

OSX / Oracle java8 üzerinde iki ve dört ile çalışır. Orijinal java ortamınızda bir sorun var gibi görünüyor (bunun doğasından bahsetmiyorsunuz)
TheMadsen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.