Skip to content

Archives

  • Leden 2022
  • Prosinec 2021
  • Listopad 2021
  • Říjen 2021
  • Září 2021

Categories

  • Žádné rubriky
Trend RepositoryArticles and guides
Articles

Spouštění příkazů shellu v Javě

On 23 října, 2021 by admin
  • Úvod
  • Runtime.exec()
  • Vykonání příkazu z řetězce
  • Určení pracovního adresáře
  • Použití proměnných prostředí
  • Spuštění souborů .bat a .sh
  • ProcessBuilder
  • ProcessBuilder: Spouštění příkazů z řetězců
  • ProcessBuilder: Místo zadávání pracovního adresáře prostřednictvím příkazu jej nastavíme programově: processBuilder.command("cmd", "/c", "dir").directory(new File("C:\Users\"));
  • ProcessBuilder: Proměnné prostředí
  • ProcessBuilder: Spouštění souborů .bat a .sh
  • Závěr

Úvod

V tomto článku se podíváme, jak můžeme využít třídy Runtime a ProcessBuilder ke spouštění příkazů a skriptů shellu v Javě.

Počítače používáme k automatizaci mnoha věcí při každodenní práci. Správci systému neustále spouštějí mnoho příkazů, z nichž některé se velmi opakují a vyžadují minimální změny mezi jednotlivými spuštěními.

Tento proces je také zralý pro automatizaci. Není třeba vše spouštět ručně. Pomocí Javy můžeme spouštět jeden nebo více příkazů shellu, spouštět skripty shellu, spouštět terminál/příkazový řádek, nastavovat pracovní adresáře a manipulovat s proměnnými prostředí prostřednictvím základních tříd.

Runtime.exec()

Třída Runtime v Javě je třída vysoké úrovně, přítomná v každé jednotlivé aplikaci Javy. Jejím prostřednictvím komunikuje samotná aplikace s prostředím, ve kterém se nachází.

Pomocí metody getRuntime() získáme runtime spojený s naší aplikací a můžeme pomocí metody exec() přímo spouštět příkazy nebo spouštět .bat/.sh soubory.

Metoda exec() nabízí několik přetížených variant:

  • public Process exec(String command) – Spustí příkaz obsažený v command v samostatném procesu.
  • public Process exec(String command, String envp) – Spustí command s polem proměnných prostředí. Jsou poskytovány jako pole řetězců podle formátu name=value.
  • public Process exec(String command, String envp, File dir) – Spustí příkaz command se zadanými proměnnými prostředí z adresáře dir.
  • public Process exec(String cmdArray) – Spustí příkaz ve formě pole řetězců.
  • public Process exec(String cmdArray, String envp) – Spustí příkaz se zadanými proměnnými prostředí.
  • public Process exec(String cmdarray, String envp, File dir) – Spustí příkaz se zadanými proměnnými prostředí z adresáře dir.

Je třeba poznamenat, že tyto procesy jsou spouštěny externě z interpretu a budou závislé na systému.

Za zmínku stojí také rozdíl mezi String command a String cmdArray. Dosahují totiž téhož. A command je tak jako tak rozdělena na pole, takže použití kterékoli z těchto dvou metod by mělo přinést stejné výsledky.

Je na vás, abyste se rozhodli, zda chcete použít exec("dir /folder") nebo exec(new String{"dir", "/folder"}.

Napíšeme si několik příkladů, abychom viděli, jak se tyto přetížené metody od sebe liší.

Vykonání příkazu z řetězce

Začněme nejjednodušším přístupem z těchto tří:

Process process = Runtime.getRuntime().exec("ping www.stackabuse.com");

Spuštěním tohoto kódu se provede příkaz, který jsme zadali ve formátu String. Po jeho spuštění však nic nevidíme.

Chceme-li ověřit, zda tento příkaz proběhl správně, budeme se chtít dostat k objektu process. Použijme BufferedReader, abychom se podívali, co se děje:

public static void printResults(Process process) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line = ""; while ((line = reader.readLine()) != null) { System.out.println(line); }}

Nyní, když spustíme tuto metodu po metodě exec(), mělo by to dát něco ve smyslu:

Pinging www.stackabuse.com with 32 bytes of data:Reply from 104.18.57.23: bytes=32 time=21ms TTL=56Reply from 104.18.57.23: bytes=32 time=21ms TTL=56Reply from 104.18.57.23: bytes=32 time=21ms TTL=56Reply from 104.18.57.23: bytes=32 time=21ms TTL=56Ping statistics for 104.18.57.23: Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),Approximate round trip times in milli-seconds: Minimum = 21ms, Maximum = 21ms, Average = 21ms

Mějte na paměti, že budeme muset získat informace o procesu z instancí Process, jak budeme procházet dalšími příklady.

Určení pracovního adresáře

Pokud bychom chtěli spustit příkaz například z určité složky, provedli bychom něco v tomto smyslu:

Process process = Runtime.getRuntime() .exec("cmd /c dir", null, new File("C:\Users\")); //.exec("sh -c ls", null, new File("Pathname")); for non-Windows usersprintResults(process);

Zde jsme metodu exec() opatřili command, null pro nové proměnné prostředí a new File(), která je nastavena jako náš pracovní adresář.

Za zmínku stojí přidání cmd /c před příkaz, například dir.

Protože pracuji ve Windows, otevře se cmd a /c provede následný příkaz. V tomto případě je to dir.

Důvod, proč to nebylo povinné pro příklad ping, ale je to povinné pro tento příklad, hezky zodpověděl uživatel SO.

Spuštění předchozího kusu kódu bude mít za následek:

Volume in drive C has no label. Volume Serial Number is XXXX-XXXX Directory of C:\Users08/29/2019 05:01 PM <DIR> .08/29/2019 05:01 PM <DIR> ..08/18/2016 09:11 PM <DIR> Default.migrated08/29/2019 05:01 PM <DIR> Public05/15/2020 11:08 AM <DIR> User 0 File(s) 0 bytes 5 Dir(s) 212,555,214,848 bytes free

Podívejme se, jak bychom mohli předchozí příkaz dodat v několika jednotlivých částech místo jednoho řetězce:

Process process = Runtime.getRuntime().exec( new String{"cmd", "/c", "dir"}, null, new File("C:\Users\")); printResults(process);

Spuštění tohoto kusu kódu bude mít také za následek:

Volume in drive C has no label. Volume Serial Number is XXXX-XXXX Directory of C:\Users08/29/2019 05:01 PM <DIR> .08/29/2019 05:01 PM <DIR> ..08/18/2016 09:11 PM <DIR> Default.migrated08/29/2019 05:01 PM <DIR> Public05/15/2020 11:08 AM <DIR> User 0 File(s) 0 bytes 5 Dir(s) 212,542,808,064 bytes free

Koneckonců, bez ohledu na přístup – použití jednoho řetězce nebo pole řetězců, bude zadaný příkaz před zpracováním základní logikou vždy rozdělen na pole.

Který z těchto způsobů chcete použít, se omezuje pouze na to, který vám připadá čitelnější.

Použití proměnných prostředí

Podívejme se, jak můžeme použít proměnné prostředí:

Process process = Runtime.getRuntime().exec( "cmd /c echo %var1%", new String{"var1=value1"}); printResults(process);

V rámci pole String můžeme zadat libovolný počet proměnných prostředí. Zde jsme právě vypsali hodnotu var1 pomocí echo.

Spuštění tohoto kódu vrátí:

value1

Spuštění souborů .bat a .sh

Někdy je prostě mnohem jednodušší vše přenést do souboru a spustit tento soubor, než vše přidávat programově.

V závislosti na operačním systému použijete buď soubory .bat nebo .sh. Vytvořme jeden s obsahem:

echo Hello World

Poté použijeme stejný postup jako dříve:

Process process = Runtime.getRuntime().exec( "cmd /c start file.bat", null, new File("C:\Users\User\Desktop\"));

Tím se otevře příkazový řádek a spustí se soubor .bat v pracovním adresáři, který jsme nastavili.

Spouštění tohoto kódu jistě dostatečně vyústí v:

Když máme o všechny přetížené signatury exec() postaráno, podívejme se na třídu ProcessBuilder a na to, jak pomocí ní můžeme spouštět příkazy.

ProcessBuilder

ProcessBuilder je základní mechanismus, který spouští příkazy, když použijeme metodu Runtime.getRuntime().exec():

/** * Executes the specified command and arguments in a separate process with * the specified environment and working directory. *...*/public Process exec(String cmdarray, String envp, File dir) throws IOException { return new ProcessBuilder(cmdarray) .environment(envp) .directory(dir) .start();}

JavaDocs pro třídu Runtime

Podíváme-li se na to, jak ProcessBuilder přijme náš vstup z metody exec() a spustí příkaz, získáme dobrou představu o tom, jak ji také použít.

Přijímá příkaz String cmdarray, a to stačí k jeho spuštění. Případně mu můžeme dodat nepovinné argumenty, jako jsou String envp a File dir.

Prozkoumejme tyto možnosti.

ProcessBuilder: Spouštění příkazů z řetězců

Místo toho, abychom mohli zadat jediný řetězec, například cmd /c dir, budeme jej muset v tomto případě rozdělit. Pokud bychom například chtěli vypsat soubory v adresáři C:/Users jako dříve, provedli bychom:

ProcessBuilder processBuilder = new ProcessBuilder();processBuilder.command("cmd", "/c", "dir C:\Users");Process process = processBuilder.start();printResults(process);

Pro skutečné vykonání Process spustíme příkaz start() a vrácenou hodnotu přiřadíme instanci Process.

Provedením tohoto kódu získáme:

 Volume in drive C has no label. Volume Serial Number is XXXX-XXXX Directory of C:\Users08/29/2019 05:01 PM <DIR> .08/29/2019 05:01 PM <DIR> ..08/18/2016 09:11 PM <DIR> Default.migrated08/29/2019 05:01 PM <DIR> Public05/15/2020 11:08 AM <DIR> User 0 File(s) 0 bytes 5 Dir(s) 212,517,294,080 bytes free

Tento přístup však není o nic lepší než předchozí. Na třídě ProcessBuilder je užitečné to, že ji lze přizpůsobit. Můžeme nastavovat věci programově, nejen pomocí příkazů.

ProcessBuilder: Místo zadávání pracovního adresáře prostřednictvím příkazu jej nastavíme programově:

processBuilder.command("cmd", "/c", "dir").directory(new File("C:\Users\"));

Zde jsme nastavili pracovní adresář stejně jako dříve, ale tuto definici jsme přesunuli mimo samotný příkaz. Spuštění tohoto kódu poskytne stejný výsledek jako minulý příklad.

ProcessBuilder: Proměnné prostředí

Pomocí metod ProcessBuilders lze snadno získat seznam proměnných prostředí ve formě Map. Je také snadné nastavit proměnné prostředí tak, aby je váš program mohl používat.

Získejme aktuálně dostupné proměnné prostředí a pak přidejme některé pro pozdější použití:

ProcessBuilder processBuilder = new ProcessBuilder();Map<String, String> environmentVariables = processBuilder.environment();environmentVariables.forEach((key, value) -> System.out.println(key + value));

Vrácené proměnné prostředí jsme zabalili do Map a spustili na ně forEach(), abychom hodnoty vypsali na naši konzolu.

Spuštěním tohoto kódu získáme seznam proměnných prostředí, které máte na svém počítači:

DriverDataC:\Windows\System32\Drivers\DriverDataHerokuPathE:\HerokuProgramDataC:\ProgramData...

Nyní do tohoto seznamu přidáme proměnnou prostředí a použijeme ji:

environmentVariables.put("var1", "value1");processBuilder.command("cmd", "/c", "echo", "%var1%");Process process = processBuilder.start();printResults(process);

Spuštěním tohoto kódu získáme:

value1

Po dokončení běhu programu samozřejmě tato proměnná v seznamu nezůstane.

ProcessBuilder: Spouštění souborů .bat a .sh

Pokud byste chtěli spustit soubor, opět bychom jen dodali instanci ProcessBuilder požadované informace:

processBuilder .command("cmd", "/c", "start", "file.bat") .directory(new File("C:\Users\User\Desktop"));Process process = processBuilder.start();

Spuštění tohoto kódu vede k otevření příkazového řádku a spuštění souboru .bat:

Závěr

V tomto článku jsme se zabývali příklady spouštění příkazů shellu v Javě. Použili jsme k tomu třídy Runtime a ProcessBuilder.

Pomocí jazyka Java můžeme spouštět jeden nebo více příkazů shellu, spouštět skripty shellu, spouštět terminál/příkazový řádek, nastavovat pracovní adresáře a manipulovat s proměnnými prostředí prostřednictvím základních tříd.

Napsat komentář Zrušit odpověď na komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *

Archivy

  • Leden 2022
  • Prosinec 2021
  • Listopad 2021
  • Říjen 2021
  • Září 2021

Základní informace

  • Přihlásit se
  • Zdroj kanálů (příspěvky)
  • Kanál komentářů
  • Česká lokalizace
  • DeutschDeutsch
  • NederlandsNederlands
  • SvenskaSvenska
  • DanskDansk
  • EspañolEspañol
  • FrançaisFrançais
  • PortuguêsPortuguês
  • ItalianoItaliano
  • RomânăRomână
  • PolskiPolski
  • ČeštinaČeština
  • MagyarMagyar
  • SuomiSuomi
  • 日本語日本語

Copyright Trend Repository 2022 | Theme by ThemeinProgress | Proudly powered by WordPress