Java kodundan Unix kabuk betiği nasıl çalıştırılır?


155

Java'dan bir Unix komutu çalıştırmak oldukça basittir.

Runtime.getRuntime().exec(myCommand);

Ancak Java kodundan bir Unix kabuk betiği çalıştırmak mümkün mü? Evetse, Java kodundan bir kabuk komut dosyası çalıştırmak iyi bir uygulama olur mu?


3
Kabuk betiği etkileşimli olduğunda işler ilginçleşir.
ernesto

myCommand değişkeni nedir bu String? evet ise, o zaman işe yaramaz, exec yöntemi String [] ve argüman gerektirir, benim cevap aşağıya bakın, mükemmel çalışıyor
Girdhar Singh Rathore

Yanıtlar:


174

Process Builder'a gerçekten bakmalısınız . Gerçekten bu tür şeyler için üretildi.

ProcessBuilder pb = new ProcessBuilder("myshellScript.sh", "myArg1", "myArg2");
 Map<String, String> env = pb.environment();
 env.put("VAR1", "myValue");
 env.remove("OTHERVAR");
 env.put("VAR2", env.get("VAR1") + "suffix");
 pb.directory(new File("myDir"));
 Process p = pb.start();

3
JAVA'dan komut dosyaları çağırmak iyi bir uygulama mı? Performans sorunları var mı?
kautuksahni

1
Komut dosyasını Java'nın yapılandırmasına bağlı olarak yürütmek için programı / bin / bash veya sh belirtmeniz gerekebileceğini unutmayın (bkz. Stackoverflow.com/questions/25647806/… )
Ben Holland

@Milhous Bunun oldukça geç olduğunu ve bazı şeylerin değişmiş olabileceğini biliyorum ama mevcut Java Süreci belgeleri için bu kabuk komut dosyaları için önerilen yöntem değildir: docs.oracle.com/javase/8/docs/api/java/lang/Process.html " İşlem oluşturma yöntemleri, yerel pencereleme işlemleri, daemon işlemleri, Microsoft Windows'daki Win16 / DOS işlemleri veya kabuk komut dosyaları gibi belirli yerel platformlardaki özel işlemler için iyi çalışmayabilir. "
Harman

24

Sen kullanabilirsiniz Apache Commons exec kütüphane de.

Misal :

package testShellScript;

import java.io.IOException;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;

public class TestScript {
    int iExitValue;
    String sCommandString;

    public void runScript(String command){
        sCommandString = command;
        CommandLine oCmdLine = CommandLine.parse(sCommandString);
        DefaultExecutor oDefaultExecutor = new DefaultExecutor();
        oDefaultExecutor.setExitValue(0);
        try {
            iExitValue = oDefaultExecutor.execute(oCmdLine);
        } catch (ExecuteException e) {
            System.err.println("Execution failed.");
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("permission denied.");
            e.printStackTrace();
        }
    }

    public static void main(String args[]){
        TestScript testScript = new TestScript();
        testScript.runScript("sh /root/Desktop/testScript.sh");
    }
}

Daha fazla referans için, Apache Doc üzerinde de bir örnek verilmiştir .


Bunu Windows'da çalıştırabilir miyim?
bekur

@KisHanSarsecHaGajjar ayrıca shellscript çıktısını yakalayıp java kullanıcı arayüzünde görüntüleyebilir. Bunu yapmak mümkün

@KranthiSama ayarlayabilirsiniz OutputStreamiçin DefaultExecuterkullanarak DefaultExecuter.setStreamHandleryakalama çıkışına yöntemi OutputStream. Daha fazla bilgi için lütfen bu konuyu inceleyin: Bir komutun çıktısını nasıl yakalayabilirim ...
Hata değil

1
Projenize Apache Commons Exec kütüphane bağımlılığını ekleme bağlantısı - commons.apache.org/proper/commons-exec/dependency-info.html
aunlead

2
en iyi çözüm.
Dev

23

Java'dan bir kabuk betiği çalıştırmanın Java ruhu içinde olmadığını söyleyebilirim . Java, çapraz platform anlamına gelir ve bir kabuk komut dosyası çalıştırmak, kullanımını yalnızca UNIX ile sınırlar.

Bununla birlikte, Java içinden bir kabuk betiği çalıştırmak kesinlikle mümkündür. Listelediğiniz sözdiziminin aynısını kullanırsınız (kendim denemedim, ancak kabuk komut dosyasını doğrudan çalıştırmayı deneyin ve bu işe yaramazsa, komut dosyasını bir komut satırı parametresi olarak geçirerek kabuğun kendisini yürütün) .


43
Evet, ama birçok yönden "Java ruhu" veya "her yerde bir kez yaz" mantra zaten bir efsanedir.
BobbyShaftoe

15
Bu konuda efsanevi olan nedir?
Chris Ballance

15
efsanevi olan, genellikle java çekirdek kütüphaneleri ile gelen insanların en iyi çabalarına rağmen farklı platformlarda tam olarak aynı çalışmayan nüansların etrafından dolaşmak için çok sayıda switchesve ififade yazmanızdır .
Brian Sweeney

2
Şaşırtıcı derecede yeterli! Yukarıdaki tüm yorumlara ve cevabına katılıyorum!
AnBisw

11
@BobbyShaftoe 16 yıldır java yazıyorum ve her zaman pencerelerde geliştirdim, tüm uygulamalarım her zaman solaris / IBM veya oracle aromalı unix kutularına konuşlandırıldı, bu yüzden neden bahsettiğiniz hakkında hiçbir fikrim yok
Kalpesh Soni

21

Bence kendi sorunuzu

Runtime.getRuntime().exec(myShellScript);

İyi bir uygulama olup olmadığı konusunda ... Java ile yapamayacağınız bir kabuk komut dosyası ile ne yapmaya çalışıyorsunuz?


Java kodumda belirli bir durum oluştuğunda farklı sunucularda birkaç dosya rsync gerekiyor benzer bir durumla karşılaştım. Daha iyi bir yol var mı?
v kumar

1
@Chris Ballance ... Bu yorumun neredeyse 10 yıl sonra olduğunu biliyorum :) ama sorunuza cevap vermek için, programımın yarım düzine aşağı akış ve yukarı akış kanallarıyla etkileşime girmesi ve kabul edilen iletişim moduna bağlı olması durumunda. Özellikle çok sayıda garip kanalla etkileşime giren bir proje üzerinde çalışırken :)
Stunner

Java'da çalışmanın başka bir yolu yoksa, işlevselliği bir kabuk komut dosyasına göndermek son bir çaba olacaktır. Çalışmayı bir kabuk komut dosyasına aktarıyorsanız, durum ve bağımlılıkları koordine etmek zorunlu olacaktır. Bazen, bir kabuk betiği tek yol ya da zaman dilimi, bunu biraz iş yapmanın tek makul yolu yapar, bu yüzden bunu yapmanın bir yolu budur.
Chris Ballance

11

Evet bunu yapmak mümkündür. Bu benim için işe yaradı.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.omg.CORBA.portable.InputStream;

public static void readBashScript() {
        try {
            Process proc = Runtime.getRuntime().exec("/home/destino/workspace/JavaProject/listing.sh /"); //Whatever you want to execute
            BufferedReader read = new BufferedReader(new InputStreamReader(
                    proc.getInputStream()));
            try {
                proc.waitFor();
            } catch (InterruptedException e) {
                System.out.println(e.getMessage());
            }
            while (read.ready()) {
                System.out.println(read.readLine());
            }
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

7

İşte benim örneğim. Umarım mantıklıdır.

public static void excuteCommand(String filePath) throws IOException{
    File file = new File(filePath);
    if(!file.isFile()){
        throw new IllegalArgumentException("The file " + filePath + " does not exist");
    }
    if(isLinux()){
        Runtime.getRuntime().exec(new String[] {"/bin/sh", "-c", filePath}, null);
    }else if(isWindows()){
        Runtime.getRuntime().exec("cmd /c start " + filePath);
    }
}
public static boolean isLinux(){
    String os = System.getProperty("os.name");  
    return os.toLowerCase().indexOf("linux") >= 0;
}

public static boolean isWindows(){
    String os = System.getProperty("os.name");
    return os.toLowerCase().indexOf("windows") >= 0;
}

5

Evet, mümkün ve cevapladınız! İyi uygulamalar hakkında, doğrudan kodunuzdan değil, dosyalardan komut başlatmak daha iyi olur. Eğer yapmak zorunda Yani Java varolan komutları (veya tek bir komut) listesini yürütmek .bat, .sh, .ksh... dosyaları. Bir dosyadaki komutların listesini yürütmeye bir örnek MyFile.sh:

    String[] cmd = { "sh", "MyFile.sh", "\pathOfTheFile"};
    Runtime.getRuntime().exec(cmd);

4

Mutlak bir yolu kodlamak zorunda kalmamak için, komut dizenizi kök dizininizdeyse bulup yürütecek olan aşağıdaki yöntemi kullanabilirsiniz.

public static void runScript() throws IOException, InterruptedException {
    ProcessBuilder processBuilder = new ProcessBuilder("./nameOfScript.sh");
    //Sets the source and destination for subprocess standard I/O to be the same as those of the current Java process.
    processBuilder.inheritIO();
    Process process = processBuilder.start();

    int exitValue = process.waitFor();
    if (exitValue != 0) {
        // check for errors
        new BufferedInputStream(process.getErrorStream());
        throw new RuntimeException("execution of script failed!");
    }
}

3

Bana gelince, her şey basit olmalı. Çalışan komut dosyası için yürütmeniz yeterlidir

new ProcessBuilder("pathToYourShellScript").start();

3

ZT yöntem Executor kütüphanesi Apache Commons Exec için bir alternatiftir. Komutları çalıştırma, çıktılarını yakalama, zaman aşımlarını ayarlama vb.

Henüz kullanmadım, ancak oldukça iyi belgelenmiş görünüyor.

Belgelerden bir örnek: Bir komutu yürütmek, stderr'i bir günlükçüye pompalamak, çıktıyı UTF8 dizesi olarak döndürmek.

 String output = new ProcessExecutor().command("java", "-version")
    .redirectError(Slf4jStream.of(getClass()).asInfo())
    .readOutput(true).execute()
    .outputUTF8();

Belgeleri Commons Exec'a göre aşağıdaki avantajları listeler:

  • Akışların iyileştirilmesi
    • Akışlara okuma / yazma
    • Stderr'ı stdout'a yönlendirme
  • Zaman aşımlarının iyileştirilmesi
  • Çıkış kodlarının gelişmiş kontrolü
  • Geliştirilmiş API
    • Oldukça karmaşık kullanım durumları için bir astar
    • İşlem çıktısını bir String'e almak için bir astar
    • Kullanılabilir İşlem nesnesine erişim
    • Zaman uyumsuz süreçler için destek ( Gelecek )
  • SLF4J API ile geliştirilmiş günlük kaydı
  • Birden çok işlem için destek

2

Java'dan Unix bash veya Windows bat / cmd betiğinin nasıl çalıştırılacağı ile ilgili bir örnek. Bağımsız değişkenler kod üzerinde iletilebilir ve koddan çıktı alınabilir. Yöntem, rastgele sayıda argümanı kabul eder.

public static void runScript(String path, String... args) {
    try {
        String[] cmd = new String[args.length + 1];
        cmd[0] = path;
        int count = 0;
        for (String s : args) {
            cmd[++count] = args[count - 1];
        }
        Process process = Runtime.getRuntime().exec(cmd);
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        try {
            process.waitFor();
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
        while (bufferedReader.ready()) {
            System.out.println("Received from script: " + bufferedReader.readLine());
        }
    } catch (Exception ex) {
        System.out.println(ex.getMessage());
        System.exit(1);
    }
}

Unix / Linux üzerinde çalışırken, Windows üzerinde çalışırken yol Unix benzeri (ayırıcı olarak '/' ile) olmalıdır - '\' kullanın. Hier, rastgele sayıda argüman alan ve her argümanı ikiye katlayan bir bash betiği (test.sh) örneğidir:

#!/bin/bash
counter=0
while [ $# -gt 0 ]
do
  echo argument $((counter +=1)): $1
  echo doubling argument $((counter)): $(($1+$1))
  shift
done

Ararken

runScript("path_to_script/test.sh", "1", "2")

Unix / Linux'ta çıktı:

Received from script: argument 1: 1
Received from script: doubling argument 1: 2
Received from script: argument 2: 2
Received from script: doubling argument 2: 4

Hier, giriş argümanlarının sayısını sayan basit bir cmd Windows komut dosyası test.cmd'dir:

@echo off
set a=0
for %%x in (%*) do Set /A a+=1 
echo %a% arguments received

Komut dosyasını Windows'ta çağırırken

  runScript("path_to_script\\test.cmd", "1", "2", "3")

Çıktı

Received from script: 3 arguments received

1

Mümkün, sadece başka bir program gibi çalıştırın. Komut dosyanızın doğru # olduğundan emin olun! (she-bang) satırını komut dosyasının ilk satırı olarak ekleyin ve dosyada yürütme izinleri olduğundan emin olun.

Örneğin, bir bash betiğiyse #! / Bin / bash'ı betiğin en üstüne koyun, ayrıca chmod + x.

Ayrıca iyi bir uygulama olarak, hayır, özellikle Java için değil, ancak büyük bir komut dosyasını taşımak için çok fazla zaman kazandırırsa ve bunu yapmak için fazladan ödeme almazsanız;) zamandan tasarruf edin, komut dosyasını ekleyin ve uzun vadeli yapılacaklar listenizde bağlantı noktasını Java'ya yerleştirin.


1
  String scriptName = PATH+"/myScript.sh";
  String commands[] = new String[]{scriptName,"myArg1", "myArg2"};

  Runtime rt = Runtime.getRuntime();
  Process process = null;
  try{
      process = rt.exec(commands);
      process.waitFor();
  }catch(Exception e){
      e.printStackTrace();
  }  

1

Bu geç bir cevap. Ancak, gelecekteki geliştiriciler için bir Spring-Boot uygulamasından yürütülecek bir kabuk komut dosyası almak için katlanmak zorunda olduğum mücadeleyi koymayı düşündüm.

  1. Spring-Boot'da çalışıyordum ve Java uygulamamdan çalıştırılacak dosyayı bulamadım ve fırlatıyordu FileNotFoundFoundException. Dosyayı resourcesdizinde tutmak zorunda kaldım pom.xmlve uygulama aşağıdaki gibi başlatılırken taranacak dosyayı ayarlamak zorunda kaldım .

    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
            <includes>
                <include>**/*.xml</include>
                <include>**/*.properties</include>
                <include>**/*.sh</include>
            </includes>
        </resource>
    </resources>
  2. Bundan sonra dosyayı yürütürken sorun yaşıyordum ve geri dönüyordu error code = 13, Permission Denied. Sonra bu komutu çalıştırarak dosyayı yürütülebilir yapmak zorunda -chmod u+x myShellScript.sh

Son olarak, dosyayı aşağıdaki kod snippet'ini kullanarak yürütebilirim.

public void runScript() {
    ProcessBuilder pb = new ProcessBuilder("src/main/resources/myFile.sh");
    try {
        Process p;
        p = pb.start();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Umarım bu birinin problemini çözer.


0

Solaris 5.10'un böyle çalıştığı şey, ./batchstart.shişletim sisteminizin bunu kullanmayı kabul edip etmediğini bilmediğim bir hile var \\. batchstart.sh. Bu çift eğik çizgi yardımcı olabilir.


0

İle düşünüyorum

System.getProperty("os.name"); 

İşletim sisteminin açık olması, destekleniyorsa kabuk / bash komut dosyalarını yönetebilir. kodu taşınabilir yapmak gerekirse.


0

linux kullanımı için

public static void runShell(String directory, String command, String[] args, Map<String, String> environment)
{
    try
    {
        if(directory.trim().equals(""))
            directory = "/";

        String[] cmd = new String[args.length + 1];
        cmd[0] = command;

        int count = 1;

        for(String s : args)
        {
            cmd[count] = s;
            count++;
        }

        ProcessBuilder pb = new ProcessBuilder(cmd);

        Map<String, String> env = pb.environment();

        for(String s : environment.keySet())
            env.put(s, environment.get(s));

        pb.directory(new File(directory));

        Process process = pb.start();

        BufferedReader inputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        BufferedWriter outputReader = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
        BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));

        int exitValue = process.waitFor();

        if(exitValue != 0) // has errors
        {
            while(errReader.ready())
            {
                LogClass.log("ErrShell: " + errReader.readLine(), LogClass.LogMode.LogAll);
            }
        }
        else
        {
            while(inputReader.ready())
            {
                LogClass.log("Shell Result : " + inputReader.readLine(), LogClass.LogMode.LogAll);
            }
        }
    }
    catch(Exception e)
    {
        LogClass.log("Err: RunShell, " + e.toString(), LogClass.LogMode.LogAll);
    }
}

public static void runShell(String path, String command, String[] args)
{
    try
    {
        String[] cmd = new String[args.length + 1];

        if(!path.trim().isEmpty())
            cmd[0] = path + "/" + command;
        else
            cmd[0] = command;

        int count = 1;

        for(String s : args)
        {
            cmd[count] = s;
            count++;
        }

        Process process = Runtime.getRuntime().exec(cmd);

        BufferedReader inputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        BufferedWriter outputReader = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
        BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));

        int exitValue = process.waitFor();

        if(exitValue != 0) // has errors
        {
            while(errReader.ready())
            {
                LogClass.log("ErrShell: " + errReader.readLine(), LogClass.LogMode.LogAll);
            }
        }
        else
        {
            while(inputReader.ready())
            {
                LogClass.log("Shell Result: " + inputReader.readLine(), LogClass.LogMode.LogAll);
            }
        }
    }
    catch(Exception e)
    {
        LogClass.log("Err: RunShell, " + e.toString(), LogClass.LogMode.LogAll);
    }
}

ve kullanım için;

ShellAssistance.runShell("", "pg_dump", new String[]{"-U", "aliAdmin", "-f", "/home/Backup.sql", "StoresAssistanceDB"});

VEYA

ShellAssistance.runShell("", "pg_dump", new String[]{"-U", "aliAdmin", "-f", "/home/Backup.sql", "StoresAssistanceDB"}, new Hashmap<>());
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.