Shell-komentojen suorittaminen Javassa
On 23 lokakuun, 2021 by adminEsittely
Tässä artikkelissa tarkastelemme, miten voimme hyödyntää Runtime
– ja ProcessBuilder
-luokkia suorittaaksemme shell-komentoja ja -skriptejä Javalla.
Käytämme tietokoneita automatisoidaksemme monia asioita päivittäisissä töissämme. Järjestelmänvalvojat suorittavat jatkuvasti monia komentoja, joista osa on hyvin toistuvia ja vaatii vain vähän muutoksia suoritusten välillä.
Tämäkin prosessi on kypsä automatisoitavaksi. Kaikkea ei tarvitse ajaa manuaalisesti. Javan avulla voimme ajaa yksittäisiä tai useita komentotulkkikomentoja, suorittaa komentotulkkiskriptejä, käyttää terminaalia/komentokehotetta, asettaa työhakemistoja ja manipuloida ympäristömuuttujia ydinluokkien avulla.
Runtime.exec()
Javan Runtime
-luokka on korkean tason luokka, joka on läsnä jokaisessa Java-sovelluksessa. Sen kautta sovellus itse kommunikoi sen ympäristön kanssa, jossa se on.
Poistamalla sovellukseemme liittyvän runtime-luokan getRuntime()
-metodin kautta voimme käyttää exec()
-metodia komentojen suorittamiseen suoraan tai .bat
/.sh
-tiedostojen suorittamiseen.
exec()
-metodi tarjoaa muutamia ylikuormitettuja variaatioita:
-
public Process exec(String command)
– Suorittaacommand
:n sisältämän komennon erillisessä prosessissa. -
public Process exec(String command, String envp)
– Suorittaacommand
:n, jossa on joukko ympäristömuuttujia. Ne annetaan merkkijonomääränä, joka noudattaa muotoaname=value
. -
public Process exec(String command, String envp, File dir)
– Suorittaacommand
:n ja määritetyt ympäristömuuttujat sisältävän komennondir
-hakemistosta. -
public Process exec(String cmdArray)
– Suorittaa komennon merkkijonomääränä. -
public Process exec(String cmdArray, String envp)
– Suorittaa komennon määritettyjen ympäristömuuttujien kanssa. -
public Process exec(String cmdarray, String envp, File dir)
– Suorittaa komennon, jossa on määritetyt ympäristömuuttujat, hakemistostadir
.
On syytä huomata, että näitä prosesseja ajetaan tulkin ulkopuolelta ja ne ovat järjestelmäriippuvaisia.
Huomionarvoista on myös String command
:n ja String cmdArray
:n ero. Niillä saavutetaan sama asia. command
pilkotaan joka tapauksessa joukoksi, joten käyttämällä mitä tahansa näistä kahdesta pitäisi saada samat tulokset.
Sinusta riippuu, haluatko käyttää exec("dir /folder")
vai exec(new String{"dir", "/folder"}
.
Kirjoitetaanpa muutama esimerkki, jotta nähdään, miten nämä ylikuormitetut metodit eroavat toisistaan.
Komennon suorittaminen Stringistä
Aloitetaan näistä kolmesta yksinkertaisimmalla lähestymistavalla:
Process process = Runtime.getRuntime().exec("ping www.stackabuse.com");
Tämän koodin suorittaminen suorittaa antamamme komennon String-muodossa. Emme kuitenkaan näe mitään, kun suoritamme tämän.
Varmistaaksemme, toimiiko tämä oikein, haluamme päästä käsiksi process
-objektiin. Käyttäkäämme BufferedReader
:tä, jotta voimme katsoa, mitä tapahtuu:
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); }}
Nyt kun ajamme tämän metodin exec()
-metodin jälkeen, sen pitäisi tuottaa jotakin seuraavanlaista:
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
Pitäkää mielessä, että meidän on poimittava prosessin tiedot Process
-instansseista, kun käymme läpi muita esimerkkejä.
Työskentelyhakemiston määrittäminen
Jos haluaisit ajaa komennon esimerkiksi tietystä kansiosta, tekisimme jotakin seuraavanlaista:
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);
Tässä olemme antaneet exec()
-metodille command
, null
uusille ympäristömuuttujille ja new File()
, joka asetetaan työskentelyhakemistoksi.
Huomionarvoista on lisätä cmd /c
ennen komentoa, kuten dir
.
Koska työskentelen Windowsissa, tämä avaa cmd
ja /c
suorittaa seuraavan komennon. Tässä tapauksessa se on dir
.
Syy siihen, miksi tämä ei ollut pakollinen ping
-esimerkissä, mutta on pakollinen tässä esimerkissä, on hienosti vastattu eräältä SO-käyttäjältä.
Edellisen koodinpätkän suorittaminen johtaa:
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
Katsotaanpa, miten voisimme toimittaa edellisen komennon useina yksittäisinä osina yhden merkkijonon sijaan:
Process process = Runtime.getRuntime().exec( new String{"cmd", "/c", "dir"}, null, new File("C:\Users\")); printResults(process);
Tämän koodinpätkän suorittaminen johtaa myös:
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
Loppujen lopuksi, riippumatta lähestymistavasta – yksittäisen merkkijonon tai merkkijonojoukon käyttämisestä – syötetty komento pilkotaan aina joukoksi ennen kuin se käsitellään taustalla olevassa logiikassa.
Kumpaa haluat käyttää, kiteytyy vain siihen, kumpi on mielestäsi luettavampi.
Ympäristömuuttujien käyttäminen
Katsotaanpa, miten voimme käyttää ympäristömuuttujia:
Process process = Runtime.getRuntime().exec( "cmd /c echo %var1%", new String{"var1=value1"}); printResults(process);
Voimme syöttää niin monta ympäristömuuttujaa kuin haluamme String-joukon sisällä. Tässä olemme juuri tulostaneet var1
:n arvon käyttämällä echo
.
Tämän koodin suorittaminen palauttaa:
value1
.bat- ja .sh-tiedostojen suorittaminen
Joskus on vain paljon helpompaa siirtää kaikki tiedostoon ja suorittaa tuo tiedosto sen sijaan, että lisättäisiin kaikki ohjelmallisesti.
Käyttöjärjestelmästäsi riippuen käytät joko .bat
– tai .sh
-tiedostoja. Luodaan sellainen, jonka sisältö on:
echo Hello World
Käytetään sitten samaa lähestymistapaa kuin aiemmin:
Process process = Runtime.getRuntime().exec( "cmd /c start file.bat", null, new File("C:\Users\User\Desktop\"));
Tämä avaa komentorivin ja ajaa .bat
-tiedoston asettamassamme työhakemistossa.
Tämän koodin suorittaminen johtaa varmasti seuraavaan tulokseen:
Kun kaikki ylikuormitetut exec()
-signatuurit on hoidettu, katsotaanpa ProcessBuilder
-luokkaa ja sitä, miten voimme suorittaa komentoja sen avulla.
ProcessBuilder
ProcessBuilder
on taustalla oleva mekanismi, joka suorittaa komennot, kun käytämme Runtime.getRuntime().exec()
-metodia:
/** * 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 for the Runtime
-luokka
Katsomalla, miten ProcessBuilder
ottaa syötteemme exec()
-metodista ja suorittaa komennon, saamme hyvän käsityksen siitä, miten sitä myös käytetään.
Se hyväksyy String cmdarray
:n, ja se riittää käynnistämään sen. Vaihtoehtoisesti voimme antaa sille valinnaisia argumentteja, kuten String envp
ja File dir
.
Tutkitaanpa näitä vaihtoehtoja.
ProcessBuilder: Komennon suorittaminen merkkijonoista
Sen sijaan, että voisimme antaa yhden merkkijonon, kuten cmd /c dir
, meidän on tässä tapauksessa pilkottava se. Jos haluaisimme esimerkiksi listata C:/Users
-hakemistossa olevat tiedostot kuten aiemmin, tekisimme näin:
ProcessBuilder processBuilder = new ProcessBuilder();processBuilder.command("cmd", "/c", "dir C:\Users");Process process = processBuilder.start();printResults(process);
Toteuttaaksemme varsinaisesti Process
:n, suoritamme start()
-komennon ja annamme palautetun arvon Process
-instanssille.
Tämän koodin suorittaminen antaa tulokseksi:
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
Tämä lähestymistapa ei kuitenkaan ole yhtään sen parempi kuin edellinenkään. ProcessBuilder
-luokassa on hyödyllistä se, että se on muokattavissa. Voimme asettaa asioita ohjelmallisesti, emme vain komentojen kautta.
ProcessBuilder: Määritä työhakemisto
Sen sijaan, että annamme työhakemiston komennon kautta, asetetaan se ohjelmallisesti:
processBuilder.command("cmd", "/c", "dir").directory(new File("C:\Users\"));
Tässä asetamme työhakemiston samaksi kuin ennenkin, mutta olemme siirtäneet tuon määritelmän pois itse komennosta. Tämän koodin suorittaminen antaa saman tuloksen kuin edellisessä esimerkissä.
ProcessBuilder: Ympäristömuuttujat
Käyttämällä ProcessBuilder
:n metodeja on helppo hakea lista ympäristömuuttujista Map
:n muodossa. Ympäristömuuttujia on myös helppo asettaa niin, että ohjelmasi voi käyttää niitä.
Haastetaan tällä hetkellä käytettävissä olevat ympäristömuuttujat ja lisätään sitten joitakin myöhempää käyttöä varten:
ProcessBuilder processBuilder = new ProcessBuilder();Map<String, String> environmentVariables = processBuilder.environment();environmentVariables.forEach((key, value) -> System.out.println(key + value));
Tässä olemme pakanneet palautetut ympäristömuuttujat Map
:ksi ja ajaneet forEach()
:n sen päälle tulostaaksemme arvot konsolillemme.
Tämän koodin suorittaminen tuottaa listan koneellasi olevista ympäristömuuttujista:
DriverDataC:\Windows\System32\Drivers\DriverDataHerokuPathE:\HerokuProgramDataC:\ProgramData...
Lisätään nyt ympäristömuuttuja tuohon listaan ja käytetään sitä:
environmentVariables.put("var1", "value1");processBuilder.command("cmd", "/c", "echo", "%var1%");Process process = processBuilder.start();printResults(process);
Tämän koodin suorittaminen tuottaa:
value1
Tietenkään ohjelman suorituksen päätyttyä tämä muuttuja ei pysy enää listalla.
ProcessBuilder: .bat- ja .sh-tiedostojen suorittaminen
Jälleen kerran, jos haluat suorittaa tiedoston, annamme vain ProcessBuilder
-instanssille tarvittavat tiedot:
processBuilder .command("cmd", "/c", "start", "file.bat") .directory(new File("C:\Users\User\Desktop"));Process process = processBuilder.start();
Tämän koodin suorittaminen johtaa siihen, että komentokehote aukeaa ja suorittaa .bat
-tiedoston:
Johtopäätös
Tässä artikkelissa tutustuimme esimerkeillä komentotulkkikomentojen suorittamiseen Javassa. Olemme käyttäneet tähän Runtime
– ja ProcessBuilder
-luokkia.
Javan avulla voimme suorittaa yksittäisiä tai useita komentotulkkikomentoja, suorittaa komentotulkkiskriptejä, ajaa terminaalin/komentokehotteen, asettaa työhakemistoja ja käsitellä ympäristömuuttujia ydinluokkien avulla.
Vastaa