Unix-komentotulkeissa kuten Bashissa on ollut vuosikaudet varsin monipuoliset tavat palata komentotulkin historiasta löytyviin komentoihin. Nuoli ylös palaa komentohistoriassa taaksepäin ja nuoli alas vie eteenpäin. Koko historian näkee komennolla "history":
$ history 1257 git remote -v 1258 cd /tmp/ --- snip --- 2242 id -un 0 2243 id -gn 0
Tämän voi yhdistää grepin kanssa:
$ history|grep remote 1264 git remote -v --- snip --
Yksi kätevimmistä on haku historiasta: ensin painetaan Ctrl-R ja sen jälkeen syötetään hakusana (alla "gpg"):
(reverse-i-search)`gpg': gpg -v --verify openvpn-2.4.6.tar.xz.asc
Mikäli järkevän oloinen komento löytyy, ajetaan se Return-näppäimellä. Jos komentoa halutaan muokata ajamatta sitä, painetaan Tab. Jos halutaan etsiä muita osumia, painetaan Ctrl-R uudelleen. Ctrl-R on erityisen kätevä silloin, kun on rakennettu rakkaudella valtavan pitkä komentorivi, joka on liian kaukana komentotulkin historiassa nuolinäppäimillä löydettäväksi.
Myös Powershellissä on mahdollista käyttää nuolinäppäimiä Bashin tapaan. Myös history-komento löytyy:
PS> Get-History Id CommandLine -- ----------- 1 cd $HOME 2 Get-ChildItem -Recurse 3 cd opt --- snip --- PS> Get-History | Where-Object { $_.CommandLine -like "*HOME*" } Id CommandLine -- ----------- 1 cd $HOME
Historiasta haku onnistuu myös kirjoittamalla # ja syöttämällä hakusana...
PS> #history
... ja painalla Tab:
PS> Get-History | Where-Object { $_.CommandLine -like "*HOME*" }
Tab-näppäimellä voi etsiä muita osumia ja Return-näppäimellä valitaan tämänhetkinen komentorivi.
Toisinaan tulee tarpeelliseksi etsiä yhdestä tai useammasta tiedostosta jotakin merkkijonoa ja tulostaa täsmäävä rivi sekä tiedosto, jossa se on, sekä rivinumero. GNU grepillä tämä onnistuu triviaalisti komennolla "grep -HN <pattern>":
$ grep -Hn REXML *.rb group_policy.rb:71: dFile = REXML::Document.new( File.new("#{dDir}\#{array[0][0]}.admx")) group_policy.rb:72: eFile = REXML::Document.new( File.new("#{eDir}\#{array[0][0]}.adml")) group_policy.rb:154: dFile = REXML::Document.new( File.new("#{dDir}\#{sys_tShort}.admx")) group_policy.rb:155: eFile = REXML::Document.new( File.new("#{eDir}\#{sys_tShort}.adml")) group_policy.rb:428: dFile = REXML::Document.new( File.new("#{dDir}\#{tShort}.admx")) group_policy.rb:429: eFile = REXML::Document.new( File.new("#{dDir}\#{adml}"))
Sama homma onnistuu myös Powershellissä, mutta hieman vaikeammin:
> Get-ChildItem . -include "*.rb" -Recurse|Select-String -Pattern "REXML" group_policy.rb:71: dFile = REXML::Document.new( File.new("#{dDir}\#{array[0][0]}.admx")) group_policy.rb:72: eFile = REXML::Document.new( File.new("#{eDir}\#{array[0][0]}.adml")) group_policy.rb:154: dFile = REXML::Document.new( File.new("#{dDir}\#{sys_tShort}.admx")) group_policy.rb:155: eFile = REXML::Document.new( File.new("#{eDir}\#{sys_tShort}.adml")) group_policy.rb:428: dFile = REXML::Document.new( File.new("#{dDir}\#{tShort}.admx")) group_policy.rb:429: eFile = REXML::Document.new( File.new("#{dDir}\#{adml}"))
Tietyn nimisten tiedostojen (tai tyyppisten) poistaminen hakemistosta on melko suoraviivaista GNU findilla:
$ ls README.txt stderr.log stdout.log $ find . -maxdepth 1 -type f -name "*.log" -exec rm -f {} + $ ls README.txt
Valinta "maxdepth 1" estää findia poistamasta tiedostoja mahdollisista alihakemistoista.
Toinen vaihtoehto on putkittaa tiedostolistaus xargsille:
$ ls README.txt stderr.log stdout.log $ ls *.log|xargs rm -f $ ls README.txt
Tässä ei kuitenkaan erotella toisistaan tiedostoja ja hakemistoja, joten myös mahdolliset .log -päätteiset hakemistot yrittäisiin poistaa siinä epäonnistuen.
Powershell-ratkaisussa yhdistetään molempia lähestymistapoja:
> Get-ChildItem . -File|Select Name Name ---- stderr.log stdout.log README.txt > Get-ChildItem . -File -Filter "*.log"|Remove-Item > Get-ChildItem . -File|Select Name Name ---- README.txt
Parametri -File näyttää hakemistosta vain tiedostot, ei hakemistoja. Jos haluttaisiin poistaa myös alihakemistoista mahdollisesti löytyvät tiedostot, pitäisi Get-ChildItemille antaa parametri -Recurse. Komento Select Name on mukana vain tulosteen selkeyttämiseksi.
Tulosteiden uudelleenohjaus ja paluuarvojen käsittely toimii lähes samoin *NIX-shelleissä ja Windowsin Powershellissä. Alla tarkistetaan Linuxin systemctl-komennolla olemassa olevan ("openvpn") ja olemattoman ("fake") palvelun tila, ohjataan sekä tuloste että virhetuloste bittitaivaaseen ja tulostetaan komennon paluuarvo:
$ systemctl status openvpn > /dev/null 2>&1 $ echo $? 0 $ systemctl status fake > /dev/null 2>&1 $ echo $? 3
Kuten näkyy, paluuarvo on 0 jos palvelu on olemassa ja 3 jos sitä ei löydy.
Powershell toimii käytännössä identtisesti (alla käytössä NSSM):
> nssm.exe status openvpn > $null 2>&1 > Write-Host $LastExitCode 0 > nssm.exe status fake > $null 2>&1 > Write-Host $LastExitCode 3
Myös Powershellissä voitaisiin käyttää muuttujaa $?, mutta se ei sisällä numeerista paluuarvoa vaan totuusarvon:
> nssm.exe status openvpn > $null 2>&1 > Write-Host $? True > nssm.exe status fake > $null 2>&1 > Write-Host $? False
Sekä *NIX-shelleissä että Powershellissä voisi tulostevirrat ohjata myös vaihtoehtoisella tavalla:
$ systemctl status openvpn > /dev/null 2> /dev/null > nssm.exe status openvpn > $null 2> $null
Powershelliä konffatessa on tullut taas törmättyä useisiin varsin käyttökelpoisiin komentoihin. Alla ei-kattava lista, sillä lisää on luvassa sopivalla hetkellä.
Hakemiston poistaminen rekursiivisesti:
$ rm -rf <hakemisto> > Remove-Item -Recurse -Path <hakemisto>
Tiedoston viimeisten rivien näyttäminen:
$ cat <tiedosto>|tail -n <rivien_määrä> > Get-Content <tiedosto> -Last <rivien_määrä>
Tiedoston ensimmäisten rivien näyttäminen
$ cat <tiedosto>|head -n <rivien_määrä> > Get-Content <tiedosto> -First <rivien_määrä>
Tiedoston rivien määrän laskeminen:
$ cat <tiedosto>|wc --lines > Get-Content <tiedosto>|Measure-Object -Line
Alla on varsin hyvä vertailu Bashin ja Powershellin komennoista englanniksi (EDIT: sivu on sittemmin valitettavasti poistunut):
Kuten näkyy, Powershellissä on valmiina melko suuri määrä UNIX-tyyppisiä komentojen aliaksia. Aliakset viittaavat kuitenkin Powershell-komentoihin, joten esimerkiksi niiden valitsimet poikkeavat merkittävästi UNIX-komentojen vastaavista.
Windows-työasemien ja -palvelinten ylläpidosta voi tehdä huomattavasti tehokkaampaa ja hauskempaa Windows Powershellillä. Aiempaan Windowsin komentoriviin (cmd.exe) verrattuna Powershell on varsin ylivoimainen. Tietyt toimet ovat Powershellissä jopa helpompia kuin Unixin komentorivissä kuten Bashissa.
Powershellissä käsitellään tekstirivien tai binääridatan sijaan objekteja. joita voidaan putkittaa komennolta toiselle. Objektien käsittely on usein huomattavasti yksinkertaisempaa kuin tekstin, koska komennoissa voidaan viitata objektien ominaisuuksiin, eikä syötettä tarvitse UNIX:in komentorivien tapaan ensin siistiä ja pilkkoa lukuisilla komennoilla (esim. sed, cut, tr ja awk) oleellisen tiedon erottelemiseksi.
Tässä blogisarjassa käydään läpi Powershelliä nimenomaan UNIX-ylläpitäjän näkökulmasta pääosin lyhyiden esimerkkien avulla. UNIX-komentorivin kehote on lyhennetty selvyyden vuoksi hieman epätyypillisesti muotoon "$" ja Powershellin muotoon ">". Esimerkkikomennot eivät ole välttämättä kaikista optimoiduimpia, vaan tavoitteena on ollut pitää UNIX:in ja Powershellin komennot mahdollisimman samankaltaisina. UNIX-komennot toimivat sellaisenaan GNU-työkaluja käyttävissä käyttöjärjestelmissä, esimerkiksi Linuxissa.
(Teksti)tiedoston sisällön näyttäminen:
$ cat <tiedostonimi> > Get-Content <tiedostonimi>
Tiedoston etsiminen nimen perusteella:
$ find . -name "*teksti*" > Get-ChildItem . -Filter "*teksti*" -Recurse
Tiedostojen listaaminen:
$ ls -l > Get-ChildItem > dir
Tekstin etsiminen tiedostosta:
$ cat tiedosto|grep teksti > Get-Content tiedosto|Select-String -Pattern "*teksti*"
Ohjeiden hakeminen:
$ man komento > Get-Help komento
Tekstin tulostaminen komentoriville:
$ echo "Tämä on lause." > Write-Host "Tämä on lause."