Skip to content

Archives

  • styczeń 2022
  • grudzień 2021
  • listopad 2021
  • październik 2021
  • wrzesień 2021

Categories

  • Brak kategorii
Trend RepositoryArticles and guides
Articles

Wykonywanie poleceń powłoki w Javie

On 23 października, 2021 by admin
  • Wprowadzenie
  • Runtime.exec()
  • Wykonanie polecenia z String
  • Określ katalog roboczy
  • Używanie zmiennych środowiskowych
  • Uruchamianie plików .bat i .sh
  • ProcessBuilder
  • ProcessBuilder: Executing Command from Strings
  • ProcessBuilder: Specify the Working Directory
  • ProcessBuilder: Environment Variables
  • ProcessBuilder: Running .bat and .sh Files
  • Podsumowanie

Wprowadzenie

W tym artykule przyjrzymy się, jak możemy wykorzystać klasy Runtime i ProcessBuilder do wykonywania poleceń powłoki i skryptów w Javie.

Korzystamy z komputerów, aby zautomatyzować wiele rzeczy w naszej codziennej pracy. Administratorzy systemów wykonują wiele poleceń przez cały czas, niektóre z nich są bardzo powtarzalne i wymagają minimalnych zmian pomiędzy kolejnymi uruchomieniami.

Ten proces jest również dojrzały do automatyzacji. Nie ma potrzeby, aby uruchamiać wszystko ręcznie. Używając Javy, możemy uruchamiać pojedyncze lub wielokrotne polecenia powłoki, wykonywać skrypty powłoki, uruchamiać terminal/polecenie prompt, ustawiać katalogi robocze i manipulować zmiennymi środowiskowymi poprzez klasy podstawowe.

Runtime.exec()

Klasa Runtime w Javie jest klasą wysokiego poziomu, obecną w każdej pojedynczej aplikacji Javy. Za jej pośrednictwem sama aplikacja komunikuje się ze środowiskiem, w którym się znajduje.

Wyodrębniając runtime związany z naszą aplikacją za pomocą metody getRuntime(), możemy użyć metody exec() do bezpośredniego wykonywania poleceń lub uruchamiania plików .bat/.sh.

Metoda exec() oferuje kilka przeciążonych odmian:

  • public Process exec(String command) – Wykonuje polecenie zawarte w command w oddzielnym procesie.
  • public Process exec(String command, String envp) – Wykonuje command, z tablicą zmiennych środowiskowych. Są one podawane jako tablica ciągów znaków, zgodnie z formatem name=value.
  • public Process exec(String command, String envp, File dir) – Wykonuje polecenie command, z podanymi zmiennymi środowiskowymi, z wnętrza katalogu dir.
  • public Process exec(String cmdArray) – Wykonuje polecenie w postaci tablicy ciągów znaków.
  • public Process exec(String cmdArray, String envp) – Wykonuje polecenie z podanymi zmiennymi środowiskowymi.
  • public Process exec(String cmdarray, String envp, File dir) – Wykonuje polecenie, z podanymi zmiennymi środowiskowymi, z wnętrza katalogu dir.

Warto zauważyć, że te procesy są uruchamiane na zewnątrz interpretera i będą zależne od systemu.

Warto również zauważyć różnicę między String command a String cmdArray. Osiągają one to samo. A command i tak jest rozbity na tablicę, więc użycie któregokolwiek z tych dwóch powinno dać takie same rezultaty.

To ty decydujesz, czy exec("dir /folder") czy exec(new String{"dir", "/folder"} jest tym, czego chcesz użyć.

Zapiszmy kilka przykładów, aby zobaczyć, jak te przeciążone metody różnią się od siebie.

Wykonanie polecenia z String

Zacznijmy od najprostszego podejścia z tych trzech:

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

Wykonanie tego kodu spowoduje wykonanie polecenia, które dostarczyliśmy w formacie String. Jednak nic nie widzimy, gdy to uruchamiamy.

Aby sprawdzić, czy to zadziałało poprawnie, będziemy chcieli uzyskać dostęp do obiektu process. Użyjmy BufferedReader, aby spojrzeć, co się dzieje:

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

Teraz, gdy uruchomimy tę metodę po metodzie exec(), powinna ona dać coś w rodzaju:

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

Pamiętajmy, że będziemy musieli wydobyć informacje o procesie z instancji Process, gdy będziemy przechodzić przez inne przykłady.

Określ katalog roboczy

Jeśli chciałbyś uruchomić polecenie z, powiedzmy, określonego folderu, zrobilibyśmy coś w stylu:

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

Tutaj, wyposażyliśmy metodę exec() w command, null dla nowych zmiennych środowiskowych i new File(), który jest ustawiony jako nasz katalog roboczy.

Na uwagę zasługuje dodanie cmd /c przed poleceniem takim jak dir.

Ponieważ pracuję na Windowsie, otwiera to cmd i /c wykonuje kolejne polecenie. W tym przypadku jest to dir.

Powód, dla którego nie było to obowiązkowe dla przykładu ping, ale jest obowiązkowe dla tego przykładu, jest ładnie odpowiedziane przez użytkownika SO.

Running the previous piece of code will result in:

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

Zobaczmy, jak moglibyśmy dostarczyć poprzednie polecenie w kilku pojedynczych częściach, zamiast pojedynczego String:

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

Running this piece of code will also result in:

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

Ostatecznie, niezależnie od podejścia – używając pojedynczego String lub tablicy String, wprowadzona przez Ciebie komenda zawsze zostanie rozbita na tablicę zanim zostanie przetworzona przez bazową logikę.

Którego z nich chcesz użyć sprowadza się tylko do tego, które z nich uważasz za bardziej czytelne.

Używanie zmiennych środowiskowych

Przyjrzyjrzyjmy się jak możemy używać zmiennych środowiskowych:

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

Możemy dostarczyć tyle zmiennych środowiskowych ile chcemy wewnątrz tablicy String. Tutaj właśnie wypisaliśmy wartość var1, używając echo.

Wykonanie tego kodu zwróci:

value1

Uruchamianie plików .bat i .sh

Czasami o wiele łatwiej jest po prostu przeładować wszystko do pliku i uruchomić ten plik, zamiast dodawać wszystko programowo.

Zależnie od systemu operacyjnego, użyjemy plików .bat lub .sh. Utwórzmy jeden z nich o następującej zawartości:

echo Hello World

Następnie zastosujmy to samo podejście, co poprzednio:

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

To otworzy wiersz poleceń i uruchomi plik .bat w katalogu roboczym, który ustawiliśmy.

Wykonanie tego kodu z pewnością zaowocuje:

Po zajęciu się wszystkimi przeciążonymi sygnaturami exec() przyjrzyjmy się klasie ProcessBuilder i temu, jak możemy wykonywać polecenia za jej pomocą.

ProcessBuilder

ProcessBuilder jest podstawowym mechanizmem, który uruchamia komendy, gdy używamy metody 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 dla klasy Runtime

Patrząc na to, jak ProcessBuilder pobiera dane wejściowe z metody exec() i uruchamia komendę, mamy dobry pomysł, jak z niej korzystać.

Przyjmuje ona String cmdarray, i to wystarczy, by ją uruchomić. Alternatywnie, możemy dostarczyć mu opcjonalne argumenty, takie jak String envp i File dir.

Poznajmy te opcje.

ProcessBuilder: Executing Command from Strings

Zamiast możliwości podania pojedynczego Stringa, takiego jak cmd /c dir, w tym przypadku będziemy musieli go rozbić. Na przykład, gdybyśmy chcieli wylistować pliki w katalogu C:/Users tak jak poprzednio, zrobilibyśmy:

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

Aby faktycznie wykonać Process, uruchamiamy polecenie start() i przypisujemy zwróconą wartość do instancji Process.

Wykonanie tego kodu da nam:

 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

Jednakże to podejście nie jest wcale lepsze od poprzedniego. To co jest przydatne w klasie ProcessBuilder to fakt, że jest ona konfigurowalna. Możemy ustawiać rzeczy programowo, a nie tylko za pomocą komend.

ProcessBuilder: Specify the Working Directory

Zamiast podawać katalog roboczy za pomocą polecenia, ustawmy go programowo:

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

Tutaj ustawiliśmy katalog roboczy na taki sam jak poprzednio, ale przenieśliśmy tę definicję poza samo polecenie. Uruchomienie tego kodu da taki sam rezultat jak w ostatnim przykładzie.

ProcessBuilder: Environment Variables

Używając metod ProcessBuilders, łatwo jest pobrać listę zmiennych środowiskowych w postaci Map. Łatwo jest również ustawić zmienne środowiskowe tak, aby Twój program mógł z nich korzystać.

Pobierzmy obecnie dostępne zmienne środowiskowe, a następnie dodajmy kilka do późniejszego wykorzystania:

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

Tutaj spakowaliśmy zwrócone zmienne środowiskowe do Map i uruchomiliśmy na niej forEach(), aby wypisać wartości na naszą konsolę.

W wyniku uruchomienia tego kodu otrzymamy listę zmiennych środowiskowych, które mamy na swoim komputerze:

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

Dodajmy teraz zmienną środowiskową do tej listy i użyjmy jej:

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

W wyniku uruchomienia tego kodu otrzymamy:

value1

Oczywiście, po zakończeniu działania programu zmienna ta nie pozostanie na liście.

ProcessBuilder: Running .bat and .sh Files

Jeśli chcielibyśmy uruchomić plik, ponownie, wystarczy, że dostarczymy instancji ProcessBuilder wymagane informacje:

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

Wykonanie tego kodu skutkuje otwarciem wiersza poleceń i wykonaniem pliku .bat:

Podsumowanie

W tym artykule zbadaliśmy przykłady uruchamiania poleceń powłoki w Javie. Wykorzystaliśmy do tego klasy Runtime i ProcessBuilder.

Używając Javy, możemy uruchamiać pojedyncze lub wielokrotne polecenia powłoki, wykonywać skrypty powłoki, uruchamiać terminal/polecenie zachęty, ustawiać katalogi robocze i manipulować zmiennymi środowiskowymi za pomocą klas podstawowych.

.

Dodaj komentarz Anuluj pisanie odpowiedzi

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Archiwa

  • styczeń 2022
  • grudzień 2021
  • listopad 2021
  • październik 2021
  • wrzesień 2021

Meta

  • Zaloguj się
  • Kanał wpisów
  • Kanał komentarzy
  • WordPress.org
  • 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