Plik, czyli zmienna.
Zmienne w PowerShellu to dość ciekawy "zwierz". Większość użytkowników spotyka się z nimi w najprostszej postaci: $zmienna. Definiujemy, modyfikujemy, używamy. I tyle. Trzeba jednak wiedzieć, że zmienne to coś więcej niż tylko "worki" na nasze obiekty, do których odnosimy się wykorzystując tę najprostszą notację. W tym artykule postaram się wspomnieć o kilku sprawach związanych ze zmiennymi, które odróżniają zmienne w PowerShellu od zmiennych wykorzystywanych w innych językach programistycznych i skryptowych. Zanim jednak o tym, przyjrzymy się nieco dokładniej temu czym jest a czym nie jest w PowerShellu nazwa zmiennej.
Jak ci na imię?
Przede wszystkim pamiętać musimy o tym, że "$" nie jest częścią nazwy zmiennej. Nazwę stanowi wszystko to, co po tym symbolu się znajduje. Informacja szczególnie istotna, jeśli zamierzamy skorzystać z poleceń operujących na zmiennych (*-Variable), bądź parametrów, które nazwę zmiennych wykorzystując (-ErrorVariable, -OutputVariable, PipelineVariable). W każdym z tych przypadków operować będziemy na nazwach zmiennych, więc jeśli chcemy błędy zapisać w zmiennej $wpadka, to składnia prezentować się będzie następująco:
Get-Process -Id 13 -ErrorVariable wpadka -ErrorAction SilentlyContinue $wpadka.Exception
Druga istotna informacja o zmiennych: notacja dolar-nazwa to tak naprawdę skrótowiec. Pełny zapis zmiennej w wyrażeniach umożliwia nam bowiem definiowanie zmiennych o w zasadzie dowolnej nazwie. By jednak ze zmiennych o nazwach "egzotycznych" móc skorzystać, nazwę taką musimy otoczyć nawiasem klamrowym:
function Get-Prompt { param ( [Parameter( Mandatory = $true )] [String]${Podaj, proszę, nazwę pliku!} ) ${Podaj, proszę, nazwę pliku!} } Get-Prompt cmdlet Get-Prompt at command pipeline position 1 Supply values for the following parameters: Podaj, proszę, nazwę pliku!:
Tu nazwa zmiennej (a raczej parametru funkcji), która stanowi pełne zdanie w języku polskim.
Dostawca dla zmiennych i…
W PowerShellu wiele zasobów oferowanych jest w formie dostawców. Dostawcy na ogół mają strukturę hierarchiczną (i do prezentowania danych o takiej strukturze były tworzone). Jest jednak kilku dostawców, które rodzą się i umierają z sesją PowerShella, a w których nie sposób odnaleźć strukturę drzewkową. Jeden z takich dostawców przeznaczony jest dla zmiennych.
Możemy więc wyświetlić zmienne zdefiniowane w aktualnym środowisku przy pomocy polecenia dir/ls – wielkie mi halo! Rzecz w tym, że to nie wszystko. Jeśli zechcemy zmienić nazwę zmiennej będziemy mogli skorzystać z polecenia Rename-Item:
Rename-Item -Path variable:\wpadka -NewName oops $oops
Jak pobrać zawartość zmiennej? Cóż, nazwa polecenia nasuwa się sama. Sprawdźmy jedynie czy polecenie zadziała zgodnie z naszymi oczekiwaniami. Dla odmiany jednak skorzystamy z aliasu:
cat Variable:\oops Get-Process : Cannot find a process with the process identifier 13.(...)
I tu zaczyna się istny "Meksyk". Relacja jest bowiem dwustronna. Zmienne to obiekty w ramach dostawców, ale obiekty w ramach dostawców możemy traktować jak zmienne. Nic tak nie przemawia do wyobraźni jak przykład "z życia wzięty", spróbujmy więc dopisać coś do pliku hosts korzystając z tej cechy dostawców w PowerShellu:
${c:\windows\system32\drivers\etc\hosts} += '127.0.0.1 powershell.pl' Test-Connection -ComputerName powershell.pl
Jak widać, tu właśnie szczególnie przyda nam się wspomniana na wstępnie składnia obejmująca nazwę zmiennej klamrami. Co jednak, gdy z klamr chcemy zrezygnować? Wystarczy wprzód zadbać o odpowiednią lokalizację w ramach wybranego dostawcy/dysku. Wówczas zamiast notacji "pełnej" wystarczy taka, która nazwę zmiennej poprzedzi nazwą dysku. Jest jedno ale: kropka (jakże często stosowana w nazwach plików…) jest jednym z symboli, które w nazwach zmiennych bez klamr nie są dozwolone. Szczęśliwie, plik hosts jest wyjątkiem od reguły. Zanim jednak dopiszemy kolejną linię do pliku stwórzmy jego kopię zapasową (z lenistwa, również bez rozszerzenia):
Push-Location C:\Windows\system32\drivers\etc $c:hostsbck = $c:hosts $c:hosts += '127.0.0.1 nowy.wpis.pl' Test-Connection -Count 1 -ComputerName nowy.wpis.pl
Na koniec wisienka na torcie: zamienimy treść obu plików miejscami. PowerShell oferuje taką możliwość w przypadku zmiennych, dlaczego więc pliki miałyby stanowić tu wyjątek? Jedna linijka kodu i już hostsbck zawiera nowy.wpis.pl a plik hosts jest od niego wolny:
$c:hosts, $c:hostsbck = $c:hostsbck, $c:hosts Get-ChildItem | Where-Object { Select-String -Pattern nowy -Path $_.FullName }
Co ciekawe: podobne możliwości oferuje dostawca dla funkcji czy aliasów. Działać to powinno dla każdego dostawcy, który rozumie koncept "zawartości", jeśli więc działa gdzieś Get-Content, notacja przeznaczona dla zmiennych również działać powinna.
[…] mamy dwie: polecenie Set-Content, lub składnia wykorzystująca zapis typowy dla zmiennych (pisałem o takim wykorzystaniu tej składni niedawno). To co mi osobiście podoba się w metodzie wykorzystującej atrybut to fakt, że definicja taka […]