1/14 Zmienne systemowe i użytkownika w skryptach Windows
2/14 1. Wprowadzenie do zmiennych w środowisku Windows

System operacyjny Microsoft Windows, niezależnie od wersji, opiera swoje działanie na rozbudowanym systemie zmiennych konfiguracyjnych, które determinują zachowanie systemu, aplikacji i skryptów. Zmienne te stanowią fundamentalny mechanizm komunikacji między systemem operacyjnym, uruchomionymi programami a skryptami automatyzującymi zadania administracyjne. Zrozumienie tego systemu jest niezbędne dla każdego, kto zamierza pisać efektywne skrypty wsadowe (batch) w języku CMD lub PowerShell, a także dla administratorów systemów zarządzających środowiskiem Windows w firmach i organizacjach.

W przeciwieństwie do innych systemów operacyjnych, Windows oferuje wielopoziomowy model zmiennych, gdzie te same zmienne mogą mieć różne wartości w zależności od kontekstu – użytkownika, sesji czy zakresu (systemowy vs użytkownik). Ta elastyczność, choć potężna, wymaga świadomego zarządzania, aby uniknąć konfliktów i nieprzewidywalnego zachowania skryptów.

3/14 2. Architektura zmiennych w Windows

System Windows przechowuje zmienne konfiguracyjne w kilku różnych lokalizacjach, tworząc hierarchiczną strukturę dziedziczenia wartości. Zmienna środowiskowa może być zdefiniowana na poziomie systemu operacyjnego (dla wszystkich użytkowników), na poziomie konta użytkownika (tylko dla jednego użytkownika) lub w obrębie pojedynczej sesji procesu (zmienne tymczasowe). Ta wielopoziomowość pozwala na elastyczne dostosowywanie środowiska do różnych potrzeb, ale wymaga zrozumienia mechanizmów priorytetów.

2.1 Poziomy zmiennych środowiskowych

W systemie Windows wyróżniamy trzy główne poziomy definicji zmiennych środowiskowych. Każdy z nich ma swoje specyficzne zastosowanie, ograniczenia i metody zarządzania.

  • Zmienne systemowe (Machine) – definiowane na poziomie całego systemu operacyjnego, dostępne dla wszystkich użytkowników i procesów. Wymagają uprawnień administratora do modyfikacji. Przechowywane w rejestrze w gałęzi HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment.
  • Zmienne użytkownika (User) – definiowane dla konkretnego konta użytkownika, przechowywane w rejestrze w gałęzi HKEY_CURRENT_USER\Environment. Nie wymagają uprawnień administratora, ale wpływają tylko na środowisko danego użytkownika.
  • Zmienne procesu (Process) – kombinacja zmiennych systemowych i użytkownika dla bieżącego procesu, uzupełniona o zmienne tymczasowe ustawione w sesji. Każdy nowo uruchomiony proces otrzymuje kopię tych zmiennych.

2.2 Mechanizm dziedziczenia i priorytetów

Gdy system Windows uruchamia nowy proces, tworzy dla niego środowisko zmiennych na podstawie zmiennych systemowych i użytkownika. Jeśli ta sama zmienna jest zdefiniowana na obu poziomach (systemowym i użytkownika), to wartość zmiennej użytkownika ma pierwszeństwo dla procesów uruchomionych w kontekście tego użytkownika. Jest to kluczowa informacja przy debugowaniu skryptów, które zachowują się inaczej dla różnych użytkowników.

Warto również wiedzieć, że zmiany w zmiennych środowiskowych (systemowych lub użytkownika) wymagają restartu procesów, które mają z nich korzystać. System Windows nie propaguje automatycznie zmian do już uruchomionych aplikacji – one nadal widzą stare wartości aż do ponownego uruchomienia. Jest to częsta przyczyna problemów po modyfikacji zmiennej PATH.

4/14 3. Wyświetlanie zmiennych środowiskowych

Poznanie aktualnie zdefiniowanych zmiennych środowiskowych jest fundamentalną umiejętnością administracyjną. Windows oferuje kilka metod wyświetlania tych zmiennych – od prostych poleceń wiersza poleceń po graficzne narzędzia systemowe i zaawansowane opcje w PowerShell.

3.1 Polecenie SET w CMD

Polecenie SET bez żadnych parametrów wyświetla listę wszystkich zmiennych środowiskowych aktualnej sesji, posortowanych alfabetycznie. Każda zmienna jest prezentowana w formacie NAZWA=WARTOŚĆ. Jest to najprostsza i najszybsza metoda przeglądania środowiska.

:: CMD - wyświetlanie wszystkich zmiennych
C:\> set
:: Wyświetl zmienne zaczynające się od określonej litery
C:\> set P
:: Wyświetl zmienną użytkownika lub systemową
C:\> set US

3.2 Polecenie ECHO z odwołaniami procentowymi

Aby wyświetlić wartość konkretnej zmiennej, używamy polecenia ECHO %NAZWA_ZMIENNEJ%. Odwołanie procentowe (%zmienna%) informuje interpreter CMD, że ma podstawić wartość zmiennej w miejsce tego oznaczenia przed wykonaniem polecenia. Jest to fundamentalna składnia dostępu do zmiennych w skryptach wsadowych.

:: CMD - wyświetlanie pojedynczych zmiennych
C:\> echo %USERNAME%
Użytkownik
C:\> echo %USERPROFILE%
C:\Users\Użytkownik
C:\> echo %TEMP%
C:\Users\Użytkownik\AppData\Local\Temp
C:\> echo %COMPUTERNAME%
MOJ-KOMPUTER
:: Wyświetlenie ścieżki systemowej (PATH) - może być bardzo długie
C:\> echo %PATH%
C:\Windows\system32;C:\Windows;C:\Program Files\...

3.3 Narzędzia graficzne Windows

Dla osób preferujących interfejs graficzny, Windows oferuje dostęp do zmiennych środowiskowych przez okno Właściwości systemu. Można je otworzyć klikając prawym przyciskiem myszy na ikonę Ten komputer (lub Mój komputer) na pulpicie lub w menu Start, wybierając Właściwości, a następnie Zaawansowane ustawienia systemu. W zakładce Zaawansowane znajduje się przycisk Zmienne środowiskowe.

Okno zmiennych środowiskowych jest podzielone na dwie sekcje: zmienne użytkownika (górna tabela) i zmienne systemowe (dolna tabela). System pozwala na tworzenie nowych zmiennych, edycję istniejących oraz usuwanie ich – przy czym modyfikacja zmiennych systemowych wymaga potwierdzenia konta administratora.

3.4 PowerShell – alternatywne metody

Windows PowerShell oferuje znacznie bardziej rozbudowane możliwości pracy ze zmiennymi środowiskowymi. Zmienne te są dostępne przez specjalny napęd Env:, który traktuje zmienne środowiskowe jak pliki w systemie plików. Ta obiektowa natura PowerShell pozwala na zaawansowane filtrowanie, sortowanie i manipulację danymi.

# PowerShell - wyświetlanie zmiennych
PS C:\> Get-ChildItem Env:
Name Value
---- -----
ALLUSERSPROFILE C:\ProgramData
...
# Pobierz konkretną zmienną
PS C:\> $env:USERNAME
Użytkownik
PS C:\> $env:PATH
C:\Windows\system32;C:\Windows;...
# Lista wszystkich zmiennych posortowana
PS C:\> Get-ChildItem Env: | Sort-Object Name
# Filtrowanie zmiennych
PS C:\> Get-ChildItem Env: | Where-Object { $_.Name -like "USER*" }
5/14 4. Kompletna lista zmiennych systemowych Windows

System Windows definiuje dziesiątki zmiennych środowiskowych, z których każda ma określone przeznaczenie. Poniżej przedstawiono pełny przegląd najważniejszych zmiennych, ich znaczenie i typowe zastosowania w skryptach administracyjnych.

4.1 Zmienne dotyczące systemu operacyjnego

  • COMPUTERNAME – nazwa komputera nadana mu w sieci. Używana w skryptach operujących na wielu maszynach do identyfikacji hosta.
  • WINDIR lub SYSTEMROOT – pełna ścieżka do katalogu głównego Windows (zazwyczaj C:\Windows). Niezbędna przy odwoływaniu się do plików systemowych.
  • SYSTEMDRIVE – litera dysku, na którym zainstalowany jest system Windows (zazwyczaj C:). Przydatna przy określaniu lokalizacji głównego dysku systemowego.
  • OS – nazwa systemu operacyjnego (np. Windows_NT). Można jej użyć do sprawdzenia typu systemu w skryptach wieloplatformowych.
  • PROCESSOR_ARCHITECTURE – architektura procesora (x86, AMD64, ARM64). Kluczowa przy skryptach wymagających różnego zachowania na różnych platformach sprzętowych.
  • NUMBER_OF_PROCESSORS – liczba zainstalowanych rdzeni procesora. Może być używana do optymalizacji skryptów wykorzystujących przetwarzanie równoległe.
  • PROCESSOR_IDENTIFIER – szczegółowy identyfikator procesora zawierający informacje o producencie i modelu.
  • PROCESSOR_LEVEL – numer poziomu modelu procesora (np. 6 dla Intel Core 2 Duo).
  • PROCESSOR_REVISION – numer rewizji procesora.

4.2 Zmienne dotyczące użytkownika

  • USERNAME – nazwa konta aktualnie zalogowanego użytkownika. Przydatna do personalizacji komunikatów i logowania.
  • USERPROFILE – pełna ścieżka do katalogu profilu użytkownika (C:\Users\NazwaUżytkownika). Zawiera wszystkie foldery użytkownika.
  • USERDOMAIN – nazwa domeny lub grupy roboczej, do której należy komputer użytkownika.
  • HOMEPATH – względna ścieżka do katalogu domowego użytkownika (np. \Users\NazwaUżytkownika). Często używana w połączeniu ze zmienną SYSTEMDRIVE.
  • HOMEDRIVE – litera dysku zawierającego katalog domowy użytkownika (zazwyczaj C:).
  • APPDATA – ścieżka do folderu danych aplikacji użytkownika (%USERPROFILE%\AppData\Roaming). Miejsce na ustawienia programów specyficzne dla użytkownika.
  • LOCALAPPDATA – ścieżka do folderu danych lokalnych (%USERPROFILE%\AppData\Local). Używane dla danych tymczasowych i specyficznych dla danej maszyny.
  • PUBLIC – ścieżka do folderu Public (C:\Users\Public). Dostępna dla wszystkich użytkowników komputera.
  • LOGONSERVER – nazwa serwera kontrolera domeny, który uwierzytelnił użytkownika.

4.3 Zmienne dotyczące ścieżek i katalogów

  • PATH – lista katalogów (oddzielonych średnikami) przeszukiwanych przy uruchamianiu programów bez podawania pełnej ścieżki. Jedna z najważniejszych zmiennych systemowych.
  • PATHEXT – lista rozszerzeń plików traktowanych jako pliki wykonywalne (.COM, .EXE, .BAT, .CMD, .VBS, .JS itd.).
  • PROGRAMFILES – ścieżka do folderu Program Files (zazwyczaj C:\Program Files). Miejsce instalacji aplikacji 64-bitowych.
  • PROGRAMFILES(X86) – ścieżka do folderu Program Files (x86) na systemach 64-bitowych (C:\Program Files (x86)).
  • COMMONPROGRAMFILES – folder plików wspólnych dla aplikacji (C:\Program Files\Common Files).
  • COMMONPROGRAMFILES(X86) – folder plików wspólnych dla aplikacji 32-bitowych.
  • PROGRAMDATA – ścieżka do folderu ProgramData (C:\ProgramData). Służy do przechowywania danych wspólnych dla wszystkich użytkowników.
  • SYSTEMROOT – pełna ścieżka do katalogu Windows (identyczna z %WINDIR%).

4.4 Zmienne dotyczące katalogów tymczasowych

  • TEMP – ścieżka do katalogu tymczasowych plików użytkownika. Skrypty powinny używać tej lokalizacji dla plików pośrednich.
  • TMP – alternatywna zmienna dla katalogu tymczasowego. Obie zmienne zazwyczaj wskazują na ten sam folder.
  • %WINDIR%\Temp – systemowy katalog tymczasowy (dla plików tymczasowych systemu operacyjnego).

4.5 Zmienne dotyczące sesji i konsoli

  • CMDCMDLINE – pełne polecenie, które uruchomiło bieżącą sesję CMD (ze ścieżką do cmd.exe i ewentualnymi parametrami).
  • CMDEXTVERSION – numer wersji rozszerzeń poleceń CMD (Command Line Extensions).
  • ERRORLEVEL – kod wyjścia ostatniego wykonanego polecenia. Wartość 0 oznacza sukces, każda inna wartość oznacza błąd.
  • RANDOM – losowa liczba całkowita z zakresu 0-32767. Przydatna przy generowaniu tymczasowych nazw plików.
  • DATE – bieżąca data w formacie ustawionym w systemie.
  • TIME – bieżący czas w formacie ustawionym w systemie.

4.6 Zmienne dotyczące sieci

  • COMPUTERNAME – nazwa komputera w sieci.
  • USERDOMAIN – domena lub grupa robocza konta użytkownika.
  • USERDNSDOMAIN – pełna domena DNS konta użytkownika (w środowisku domenowym).
  • LOGONSERVER – serwer uwierzytelniania.
  • SESSIONNAME – nazwa bieżącej sesji (np. Console, RDP-Tcp#0 dla sesji zdalnych).
  • CLIENTNAME – nazwa komputera klienta w sesji RDP.

4.7 Zmienne specjalne interpretera CMD

  • %0 – pełna ścieżka i nazwa aktualnie wykonywanego skryptu (.bat lub .cmd).
  • %1 do %9 – argumenty przekazane do skryptu (pozycje 1-9).
  • %* – wszystkie argumenty skryptu (z wyjątkiem %0).
  • %~dp0 – rozwinięcie zmiennej %0: dysk i ścieżka do katalogu skryptu.
  • %~nx0 – rozwinięcie zmiennej %0: sama nazwa skryptu (n) z rozszerzeniem (x).
  • ERRORLEVEL – kod wyjścia ostatniego polecenia (0 = sukces).
6/14 5. Tworzenie i modyfikacja zmiennych

Tworzenie i modyfikacja zmiennych środowiskowych w Windows różni się w zależności od wymaganego poziomu trwałości. Zmienne ustawione za pomocą polecenia SET istnieją tylko w bieżącej sesji wiersza poleceń. Aby utworzyć zmienne trwałe, należy użyć polecenia SETX lub bezpośrednio edytować rejestr systemowy.

5.1 Zmienne tymczasowe – polecenie SET

Polecenie SET służy do tworzenia zmiennych tymczasowych, które istnieją tylko w bieżącej sesji CMD. Po zamknięciu okna wiersza poleceń wszystkie tak utworzone zmienne zostają utracone. Jest to przydatne przy testowaniu skryptów i tworzeniu zmiennych roboczych w skryptach, które nie powinny wpływać na globalne środowisko.

:: CMD - tworzenie zmiennej tymczasowej
C:\> set MOJA_ZMIENNA=Tekst testowy
C:\> echo %MOJA_ZMIENNA%
Tekst testowy
:: Zmienna istnieje tylko w tej sesji
C:\> set MOJA_ZMIENNA= # usunięcie zmiennej
:: Tworzenie zmiennej zawierającej ścieżkę (bez cudzysłowów w przypisaniu)
C:\> set MOJ_KATALOG=C:\Program Files\MojaAplikacja
:: Zmienne numeryczne
C:\> set /a WYNIK=5+3
C:\> echo %WYNIK%
8

5.2 Zmienne trwałe – polecenie SETX

Polecenie SETX (dostępne od Windows Vista i Server 2003) tworzy zmienne trwałe, które przetrwają zamknięcie sesji i restart systemu. Jest to podstawowe narzędzie do trwałej modyfikacji zmiennych środowiskowych w skryptach administracyjnych i automatyzacji. Warto jednak pamiętać, że SETX modyfikuje rejestr, ale nie wpływa na już uruchomione sesje – wymagają one restartu.

:: SETX - tworzenie zmiennej użytkownika (trwała)
C:\> setx MOJA_ZMIENNA "Wartość trwała"
SUCCESS: Specified value was saved.
:: SETX - tworzenie zmiennej systemowej (wymaga admina)
C:\> setx MOJA_ZMIENNA_SYSTEMOWA "Wartość" /M
SUCCESS: Specified value was saved.
:: SETX - dodawanie do zmiennych systemowych (wymaga administratora)
C:\> setx MOJA_SCIESZKA "C:\MojeProgramy" /M
:: UWAGA: SETX rozwija zmienne %NAZWA% przed zapisem – zapisuje wartość statyczną, a nie dynamiczne odniesienie!
:: Poniższe polecenie tworzy zmienną NOWA_SCIESZKA z bieżącą rozwiniętą wartością PATH.
C:\> setx NOWA_SCIESZKA "%PATH%;C:\NowyFolder"
:: Do trwałej modyfikacji PATH (lub dla długich wartości) użyj rejestru lub PowerShell:
# PowerShell - dodawanie do PATH użytkownika
PS C:\> $sciezka = [Environment]::GetEnvironmentVariable("Path", "User")
PS C:\> [Environment]::SetEnvironmentVariable("Path", "$sciezka;C:\NowyFolder", "User")

5.3 Modyfikacja zmiennej PATH

Zmienna PATH jest szczególnym przypadkiem, ponieważ zawiera listę wielu ścieżek oddzielonych średnikami. Dodawanie nowych ścieżek wymaga odczytania obecnej wartości, dołączenia nowej ścieżki i zapisu z powrotem. Jest to operacja, którą administratorzy wykonują bardzo często – przy instalacji nowych programów, kompilatorów, interpreterów języków programowania czy narzędzi deweloperskich.

:: CMD - dodawanie ścieżki do PATH (tymczasowo, dla sesji)
C:\> set PATH=%PATH%;C:\MojeNarzedzia
C:\> echo %PATH%
...;C:\MojeNarzedzia
:: CMD – TRWAŁE DODANIE DO PATH (uwaga: rozwija zmienne, limit 1024 znaków)
C:\> setx PATH "%PATH%;C:\MojeNarzedzia"
:: UWAGA: setx NADPISUJE całą zmienną rozwiniętą wartością – nie tworzy dynamicznego odniesienia!
:: Do bezpiecznej modyfikacji PATH użyj PowerShell (patrz przykład poniżej).
# PowerShell - bezpieczne dodawanie do PATH
PS C:\> $userPath = [Environment]::GetEnvironmentVariable("Path", "User")
PS C:\> if ($userPath -notlike "*C:\MojeNarzedzia*") {
[Environment]::SetEnvironmentVariable(
"Path",
"$userPath;C:\MojeNarzedzia",
"User"
)
}
# PowerShell - sprawdzenie czy ścieżka istnieje w PATH
PS C:\> $env:PATH -split ';' | Select-String "MojeNarzedzia"
7/14 6. Zmienne lokalne w skryptach CMD

Pisanie profesjonalnych skryptów wsadowych wymaga zrozumienia mechanizmów izolacji zmiennych. Bez odpowiednich technik, zmienne zdefiniowane wewnątrz skryptu mogą "wyciekać" do sesji użytkownika po zakończeniu jego działania, powodując nieoczekiwane zachowanie kolejnych poleceń i programów. Polecenia setlocal i endlocal stanowią fundamentalne narzędzia kontroli zasięgu zmiennych.

6.1 Polecenie SETLOCAL – początek zakresu lokalnego

Polecenie setlocal inicjalizuje nowy lokalny zakres zmiennych dla skryptu. Od tego momentu wszystkie zmienne utworzone w skrypcie będą lokalne i zostaną automatycznie usunięte po zakończeniu skryptu lub wykonaniu polecenia endlocal. Co więcej, wszelkie modyfikacje zmiennych środowiskowych wewnątrz zakresu setlocal nie wpływają na zmienne globalne – po zakończeniu zakresu oryginalne wartości są przywracane.

:: CMD - podstawowe użycie SETLOCAL
@echo off
:: Początek zakresu lokalnego - OBOWIĄZKOWE w profesjonalnych skryptach
setlocal
echo Przed modyfikacją:
echo TEMP = %TEMP%
set TEMP=C:\MojeTemp
echo.
echo Po modyfikacji (lokalnie):
echo TEMP = %TEMP%
TEMP = C:\MojeTemp
:: Koniec zakresu - wszystko się resetuje
endlocal
echo.
echo Po endlocal:
echo TEMP = %TEMP%
TEMP = C:\Users\Użytkownik\AppData\Local\Temp (oryginalna wartość)

6.2 Zmienne globalne vs lokalne – pułapki

Bez użycia setlocal, każda zmienna zdefiniowana w skrypcie staje się zmienną globalną sesji, w której skrypt został uruchomiony. Może to prowadzić do poważnych problemów: skrypt może niechcący nadpisać zmienne systemowe, zmienne użytkownika pozostaną po zakończeniu skryptu, a kolejne uruchomienia tego samego skryptu mogą dawać różne wyniki z powodu nagromadzonych zmiennych.

:: CMD - PRZYKŁAD BŁĘDU: brak SETLOCAL
@echo off
set MOJA_ZMIENNA= Wartość ze skryptu
:: Po zakończeniu skryptu MOJA_ZMIENNA nadal istnieje!
:: POPRAWNY skrypt
@echo off
setlocal
set MOJA_ZMIENNA=Wartość lokalna
echo %MOJA_ZMIENNA%
:: Po zakończeniu skryptu zmienna znika
endlocal
:: (endlocal jest opcjonalne na końcu skryptu)

6.3 Endlocal – jawny koniec zakresu

Polecenie endlocal kończy zakres lokalny utworzony przez ostatnie setlocal i przywraca wszystkie zmienne do stanu sprzed wywołania setlocal. Można użyć go jawnie wewnątrz skryptu (np. przed wyjściem z funkcji), ale interpreter CMD automatycznie wykonuje endlocal na końcu każdego skryptu uruchomionego z setlocal.

:: CMD - endlocal wewnątrz skryptu
@echo off
setlocal
set ZMIENNA_SESJI=Tymczasowa
echo Zmienna: %ZMIENNA_SESJI%
:: Warunkowe wyjście z zachowaniem czystości środowiska
if not exist plik.txt (
echo Plik nie istnieje!
endlocal
exit /b 1
)
:: Dalsza część skryptu...
endlocal

6.4 Przekazywanie wartości przez endlocal

Istnieje zaawansowany mechanizm pozwalający na przekazanie wartości zmiennej lokalnej na zewnątrz zakresu setlocal. Składnia endlocal & set ZMIENNA=%WARTOSC% umożliwia "wyeksportowanie" wartości zmiennej lokalnej po zakończeniu zakresu. Technika ta jest szczególnie przydatna w pseudo-funkcjach skryptowych.

:: CMD - przekazywanie wartości przez endlocal
@echo off
setlocal
set LOKALNY_WYNIK=42
:: Przekazanie wartości na zewnątrz
endlocal & set WYNIK_GLOBALNY=%LOKALNY_WYNIK%
echo Po endlocal: WYNIK_GLOBALNY=%WYNIK_GLOBALNY%
Po endlocal: WYNIK_GLOBALNY=42
:: Przykład praktyczny - funkcja obliczająca
@echo off
setlocal
call :dodaj 10 20
echo Wynik: %SUMA%
goto :eof
:dodaj
set /a temp=%1+%2
endlocal & set SUMA=%temp%
goto :eof
8/14 7. Rozszerzenie zmiennych – Delayed Expansion

Jednym z najczęstszych źródeł problemów dla początkujących programistów skryptów CMD jest mechanizm rozszerzenia zmiennych. Interpreter CMD parsuje i podstawia wartości zmiennych w momencie odczytu linii, a nie w momencie jej wykonania. Prowadzi to do nieoczekiwanych zachowań wewnątrz pętli i instrukcji warunkowych. Rozwiązaniem jest rozszerzenie opóźnione (delayed expansion).

7.1 Problem – standardowe rozszerzenie

W standardowym trybie interpreter CMD najpierw odczytuje całą linię polecenia, podstawiając wartości wszystkich zmiennych, a dopiero potem wykonuje wynikowe polecenie. Dla większości przypadków jest to zachowanie pożądane. Problem pojawia się, gdy zmieniamy wartość zmiennej wewnątrz pętli – interpreter użyje wartości sprzed pętli, ponieważ podstawienie nastąpiło przed rozpoczęciem wykonywania.

:: CMD - TYPOWY BŁĄD: zmienna w pętli
@echo off
set LICZNIK=0
for %%f in (plik1.txt plik2.txt plik3.txt) do (
set /a LICZNIK+=1
echo Licznik: %LICZNIK%
)
Licznik: 0 (BŁĄD! Zawsze 0)
Licznik: 0
Licznik: 0
:: Dlaczego? Interpreter "zobaczył" %LICZNIK% jako 0
:: na początku i już nigdy go nie aktualizował!

7.2 Rozwiązanie – enabledelayedexpansion

Włączenie rozszerzenia opóźnionego za pomocą setlocal enabledelayedexpansion zmienia sposób podstawiania zmiennych. Zamiast używać składni %zmienna%, zmienne są teraz odczytywane dynamicznie z użyciem składni !zmienna!. Dzięki temu wartość zmiennej jest pobierana w momencie wykonania danej linii, a nie na etapie parsowania.

:: CMD - POPRAWNIE: rozszerzenie opóźnione
@echo off
setlocal enabledelayedexpansion
set LICZNIK=0
for %%f in (plik1.txt plik2.txt plik3.txt) do (
set /a LICZNIK+=1
echo Licznik: !LICZNIK!
)
Licznik: 1
Licznik: 2
Licznik: 3
:: Ważne: zmienne w pętli używają !zmienna!
:: Zmienne POZA pętlą mogą nadal używać %zmienna%

7.3 Zastosowania praktyczne delayed expansion

Rozszerzenie opóźnione jest niezbędne w wielu scenariuszach skryptowych. Oprócz pętli zliczających, jest ono konieczne przy manipulowaniu zmiennymi wewnątrz bloków if, for, a także przy budowaniu dynamicznych komunikatów i ścieżek.

:: CMD - rozszerzenie opóźnione w instrukcji if
@echo off
setlocal enabledelayedexpansion
set AKCJA=START
if "%AKCJA%"=="START" (
set STATUS=Uruchamianie
echo !STATUS!...
) else if "%AKCJA%"=="STOP" (
set STATUS=Zatrzymywanie
echo !STATUS!...
)
:: CMD - dynamiczne budowanie ścieżki w pętli
setlocal enabledelayedexpansion
set KATALOG_GLOWNY=C:\Dane
for %%d in (Zdjecia Dokumenty Muzyka) do (
set PELNA_SCIESZKA=!KATALOG_GLOWNY!\%%d
if exist "!PELNA_SCIESZKA!" (
echo Znaleziono: !PELNA_SCIESZKA!
)
)
9/14 8. Parametry wiersza poleceń i zmienne specjalne

Skrypty wsadowe mogą przyjmować argumenty przekazywane przy ich uruchomieniu. Argumenty te są dostępne przez specjalne zmienne pozycyjne (%0, %1, %2, ... %9), które pozwalają na tworzenie elastycznych skryptów reagujących na różne dane wejściowe. Mechanizm ten jest fundamentalny dla automatyzacji zadań administracyjnych.

8.1 Zmienne pozycyjne

Zmienne %1 do %9 przechowują kolejne argumenty przekazane do skryptu, gdzie %1 to pierwszy argument, %2 to drugi, i tak dalej. Zmienna %0 zawsze zawiera nazwę samego skryptu wraz z pełną ścieżką. Argumenty są rozdzielane spacjami – aby przekazać argument zawierający spację, należy go ująć w cudzysłowy.

:: Skrypt: args.bat
@echo off
echo Nazwa skryptu: %0
echo Pierwszy argument: %1
echo Drugi argument: %2
echo Trzeci argument: %3
echo.
echo Wszystkie argumenty: %*
:: Wywołanie: args.bat plik.txt "kopia zapasowa" /v
:: Wynik:
Nazwa skryptu: C:\Scripts\args.bat
Pierwszy argument: plik.txt
Drugi argument: kopia zapasowa
Trzeci argument: /v
Wszystkie argumenty: plik.txt "kopia zapasowa" /v

8.2 Rozwinięcia zmiennej %0

Zmienna %0 wspiera specjalne rozwinięcia zwane "parameter extensions", które pozwalają na wyodrębnienie konkretnych części ścieżki lub nazwy pliku. Jest to niezwykle przydatne, gdy skrypt potrzebuje poznać własną lokalizację lub operować na własnej nazwie.

:: Rozwinięcia zmiennej %0
:: Zakładając, że skrypt to C:\Scripts\moj_skrypt.bat
echo Ścieżka: %~dp0 # C:\Scripts\
echo Pelna nazwa: %~nx0 # moj_skrypt.bat
echo Sama nazwa: %~n0 # moj_skrypt
echo Rozszerzenie: %~x0 # .bat
echo Katalog: %~dp0 # C:\Scripts\
echo Dysk: %~d0 # C:
:: Praktyczny przykład - skrypt w swoim własnym katalogu
@echo off
setlocal
set SKRYPT_DIR=%~dp0
cd /d "%SKRYPT_DIR%"
echo Praca w katalogu skryptu: %CD%

8.3 Obsługa błędów – zmienna ERRORLEVEL

Zmienna ERRORLEVEL (dostępna jako %ERRORLEVEL%) przechowuje kod wyjścia ostatnio wykonanego polecenia lub programu. Konwencja jest prosta: wartość 0 oznacza sukces, każda inna wartość oznacza błąd (zazwyczaj 1, ale programy mogą zwracać różne kody błędów dla różnych sytuacji). Sprawdzanie ERRORLEVEL jest fundamentem obsługi błędów w skryptach wsadowych.

:: CMD - sprawdzanie ERRORLEVEL
@echo off
setlocal
copy plik.txt kopia.txt
if %ERRORLEVEL% neq 0 (
echo BŁĄD: Nie udało się skopiować pliku!
exit /b %ERRORLEVEL%
)
echo Plik skopiowany pomyślnie.
:: Alternatywna składnia (&& i ||)
copy plik.txt kopia.txt && echo Sukces!
copy plik.txt kopia.txt || echo Niepowodzenie!
:: Sprawdzanie przed operacją
if %ERRORLEVEL% equ 0 (
echo Ostatnia operacja zakończyła się sukcesem.
) else (
echo Ostatnia operacja nie powiodła się (kod: %ERRORLEVEL%).
)
10/14 9. Funkcje i procedury w skryptach CMD

CMD nie posiada natywnego wsparcia dla funkcji w rozumieniu języków programowania, ale oferuje mechanizm pseudo-funkcji oparty na etykietach i poleceniu call. Ten sposób organizacji kodu pozwala na wielokrotne użycie tego samego fragmentu kodu z różnymi parametrami, co znacząco poprawia czytelność i możliwość utrzymania skryptów.

9.1 Tworzenie pseudo-funkcji

Pseudo-funkcję tworzymy poprzez zdefiniowanie etykiety (poprzedzonej dwukropkiem) i wywołanie jej za pomocą polecenia call :nazwa_etykiety. Parametry są przekazywane jako %1, %2 itd. w kontekście wywołania. Aby funkcja zwróciła wartość, używamy techniki endlocal z przekazaniem zmiennej.

:: CMD - pseudo-funkcje
@echo off
setlocal
:: Wywołanie funkcji z parametrami
call :powitanie Jan
call :powitanie Anna
:: Funkcja z parametrem
goto :eof
:powitanie
echo Witaj, %1!
goto :eof
:: Druga funkcja - obliczenia
:oblicz_sume
setlocal
set /a wynik=%1+%2
endlocal & set SUMA=%wynik%
goto :eof
:: Użycie funkcji obliczającej
call :oblicz_sume 5 3
echo Suma: %SUMA%
Suma: 8

9.2 Zmienne lokalne w pseudo-funkcjach

Kluczowym aspektem pisania profesjonalnych pseudo-funkcji jest izolowanie zmiennych wewnętrznych za pomocą setlocal. Bez tego, zmienne tymczasowe używane w funkcji "wyciekną" do głównego zakresu skryptu i mogą nadpisać zmienne o tych samych nazwach używane w innych częściach kodu.

:: CMD - pseudo-funkcja ze zmiennymi lokalnymi
@echo off
setlocal
set GLOWNA_ZMIENNA=wartość_glowna
call :funkcja_zmieniajaca
echo Po wywołaniu: GLOWNA_ZMIENNA=%GLOWNA_ZMIENNA%
Po wywołaniu: GLOWNA_ZMIENNA=wartość_glowna
goto :eof
:funkcja_zmieniajaca
setlocal
:: Zmienna tymczasowa - nie wpłynie na zmienną główną!
set GLOWNA_ZMIENNA=zmieniona_lokalnie
echo W funkcji: GLOWNA_ZMIENNA=%GLOWNA_ZMIENNA%
endlocal
goto :eof

9.3 Biblioteki funkcji – include zewnętrzne

W bardziej zaawansowanych projektach skryptowych warto wydzielić wspólne funkcje do osobnych plików i wywoływać je z głównych skryptów. CMD nie posiada natywnego mechanizmu include, ale można go zasymulować przez wywołanie biblioteki z nazwą funkcji jako pierwszym parametrem: call biblioteka.bat :nazwa_funkcji argumenty.

:: Plik: funkcje.bat (biblioteka)
@echo off
:: Dyspozycja – wywołanie żądanej funkcji z pozostałymi argumentami
call %*
goto :eof
:: ============================================
:loguj
echo [%DATE% %TIME%] %~1
goto :eof
:blad
echo BLAD: %~1 >&2
exit /b 1
:: Plik: main.bat (główny skrypt)
@echo off
setlocal
:: Wywołanie funkcji z biblioteki
call funkcje.bat :loguj "Rozpoczęcie pracy"
call funkcje.bat :loguj "Wszystko OK"
11/14 10. Zmienne tablicowe i zaawansowane operacje

Klasyczne CMD nie wspiera natywnie tablic ani zaawansowanych struktur danych, ale można je symulować za pomocą zmiennych z indeksami. Ta technika pozwala na przechowywanie wielu wartości pod powiązanymi nazwami i iterowanie po nich w pętlach. Dla bardziej zaawansowanych operacji na danych strukturalnych warto rozważyć PowerShell.

10.1 Symulacja tablic

Tablicę symulujemy przez definiowanie zmiennych z sufiksem indeksu, na przykład ELEMENT_1, ELEMENT_2. Następnie możemy iterować po indeksach za pomocą pętli for z poleceniem /L (sekwencja liczb).

:: CMD - symulacja tablicy
@echo off
setlocal enabledelayedexpansion
:: Definicja "tablicy"
set ELEMENTY[0]=Pierwszy
set ELEMENTY[1]=Drugi
set ELEMENTY[2]=Trzeci
set ELEMENTY[3]=Czwarty
set ROZMIAR=4
:: Dostęp do elementu
echo Drugi element: !ELEMENTY[1]!
:: Iteracja po tablicy
for /L %%i in (0,1,3) do (
echo Element %%i: !ELEMENTY[%%i]!
)
Element 0: Pierwszy
Element 1: Drugi
Element 2: Trzeci
Element 3: Czwarty

10.2 Operacje na ciągach

CMD oferuje ograniczone ale użyteczne możliwości operacji na ciągach tekstowych. Możemy wycinać substringi, pobierać długość ciągu oraz manipulować zmiennymi za pomocą specjalnych rozszerzeń.

:: CMD - operacje na ciągach
set TEKST=Ala ma kota
:: Pobranie substringa (od pozycji 0, długość 3)
echo %TEKST:~0,3% Ala
:: Pobranie substringa od końca (3 ostatnie znaki)
echo %TEKST:~-4% kota
:: Zamiana tekstu w zmiennej
set NOWY=%TEKST:kota=psa%
echo %NOWY% Ala ma psa
:: Usunięcie tekstu (od początku do pierwszego wystąpienia)
set BEZ_ALA=%TEKST:Ala =%
echo %BEZ_ALA% ma kota
:: Użycie w pętli z delayed expansion
setlocal enabledelayedexpansion
set ZMIENNA=abcdef
echo Pierwsze 3: !ZMIENNA:~0,3!
echo Ostatnie 2: !ZMIENNA:~-2!
12/14 11. Zaawansowane techniki i best practices

Profesjonalne skrypty CMD wymagają stosowania sprawdzonych wzorców i praktyk, które zapewniają ich niezawodność, czytelność i łatwość utrzymania. Poniżej przedstawiono kluczowe zasady i techniki stosowane przez doświadczonych administratorów.

11.1 Szablony profesjonalnego skryptu

Każdy profesjonalny skrypt CMD powinien rozpoczynać się od określonego zestawu instrukcji inicjalizujących. Obejmuje to wyłączenie wyświetlania poleceń (@echo off), włączenie lokalnego zakresu zmiennych, włączenie rozszerzenia opóźnionego (jeśli potrzebne), a także opcjonalnie włączenie obsługi błędów za pomocą goto :eof na końcu kodu właściwego.

:: Profesjonalny szablon skryptu CMD
@echo off
:: =========================================================
:: Nazwa skryptu: backup.bat
:: Autor: Admin
:: Data: 2026-03-26
:: Opis: Automatyczna kopia zapasowa danych
:: =========================================================
:: Wymuszenie lokalnego zakresu i rozszerzenia opóźnionego
setlocal enabledelayedexpansion
:: Flagi błędów
set BLAD=0
:: Konfiguracja
set KATALOG_ZRODLOWY=C:\Dane
set KATALOG_DOCELOWY=E:\Backup
set LOG_FILE=%TEMP%\backup.log
:: Sprawdzenie wymagań
if not exist "%KATALOG_ZRODLOWY%" (
echo BLAD: Katalog źródłowy nie istnieje!
set BLAD=1
goto :koniec
)
:: Główna logika skryptu...
:koniec
if %BLAD% equ 0 (
echo Operacja zakończona sukcesem.
) else (
echo Operacja zakończona z błędami.
)
endlocal
exit /b %BLAD%

11.2 Walidacja zmiennych i argumentów

Przed użyciem zmiennych w krytycznych operacjach zawsze należy sprawdzać ich wartość. Dotyczy to zwłaszcza argumentów przekazywanych do skryptu, zmiennych konfiguracyjnych i ścieżek do plików. Walidacja zapobiega nieprzewidywalnym błędom i ułatwia diagnozowanie problemów.

:: CMD - walidacja argumentów
@echo off
setlocal
:: Sprawdzenie liczby argumentów
if "%~1"=="" (
echo Użycie: %0 ^
echo.
echo Przyklad: %0 C:\dane\plik.txt
exit /b 1
)
:: Sprawdzenie czy argument jest ścieżką do pliku
if not exist "%~1" (
echo BLAD: Plik "%~1" nie istnieje!
exit /b 2
)
:: Sprawdzenie rozszerzenia
set EXTENSION=%~x1
if not "%EXTENSION%"==".txt" (
echo BLAD: Oczekiwano pliku .txt, otrzymano %EXTENSION%
exit /b 3
)
:: Wszystkie walidacje przeszły
echo Przetwarzanie pliku: %~nx1

11.3 Obsługa ścieżek z białymi znakami

Ścieżki do folderów i plików często zawierają spacje, szczególnie w systemach Windows z domyślnymi lokalizacjami (np. "C:\Program Files"). Skrypty muszą prawidłowo obsługiwać takie ścieżki poprzez umieszczanie ich w cudzysłowach. Polecenie set "zmienna=wartość" automatycznie obcina białe znaki wokół wartości.

:: CMD - obsługa ścieżek z białymi znakami
@echo off
setlocal
:: Definicja ścieżki z białymi znakami
set "SCIEZKA=C:\Program Files\Moja Aplikacja\plik.txt"
set "SCIEZKA2=C:\Documents and Settings\Użytkownik\Desktop"
:: Użycie ścieżki - ZAWSZE w cudzysłowach
if exist "%SCIEZKA%" (
echo Znaleziono: "%SCIEZKA%"
)
:: Ustawienie katalogu roboczego z białymi znakami
cd /d "%SCIEZKA2%"
:: Pętla po plikach - ścieżka w cudzysłowach
for %%f in ("%SCIEZKA%") do (
echo Plik: %%~nxf
echo Ścieżka: "%%~dpf"
)
13/14 12. Typowe błędy i ich rozwiązania

Znajomość typowych błędów i pułapek związanych ze zmiennymi w CMD pozwala na szybsze debugowanie i pisanie bardziej niezawodnego kodu. Poniżej przedstawiono najczęstsze problemy wraz z ich rozwiązaniami.

12.1 Błędy składniowe przy definiowaniu zmiennych

Najczęstszym błędem jest umieszczanie spacji wokół operatora przypisania. W CMD set ZMIENNA = wartość tworzy zmienną o nazwie "ZMIENNA " (z końcową spacją), podczas gdy set ZMIENNA=wartość tworzy zmienną "ZMIENNA" z wartością "wartość". Podobnie, przypisanie wartości z białymi znakami wymaga cudzysłowów lub specjalnej składni.

:: BŁĄD: spacje wokół =
C:\> set ZMIENNA = wartość
C:\> echo %ZMIENNA%
ECHO jest wyłączone.
:: (pusta bo zmienna "ZMIENNA " nie istnieje)
:: POPRAWNIE: bez spacji
C:\> set ZMIENNA=wartość
C:\> echo %ZMIENNA%
wartość
:: POPRAWNIE dla wartości z białymi znakami
C:\> set "ZMIENNA=tekst ze spacjami"
C:\> echo %ZMIENNA%
tekst ze spacjami

12.2 Problemy z podstawianiem zmiennych w warunkach

Instrukcje warunkowe if i pętle for wymagają szczególnej uwagi przy używaniu zmiennych. Brak cudzysłowów wokół zmiennej zawierającej ścieżkę może spowodować błąd składniowy, jeśli ścieżka zawiera białe znaki. Zawsze używaj cudzysłowów w instrukcjach porównania.

:: BŁĄD: brak cudzysłowów w porównaniu
set SCIEZKA=C:\Program Files\App
if %SCIEZKA%==C:\Test (
:: BŁĄD! "Program Files" rozbije się na dwa argumenty
)
:: POPRAWNIE: z cudzysłowami
if "%SCIEZKA%"=="C:\Test" (
echo To jest ten katalog!
)
:: POPRAWNIE z setlocal enabledelayedexpansion
setlocal enabledelayedexpansion
if "!SCIEZKA!"=="C:\Test" (
echo To jest ten katalog!
)

12.3 Zmienne środowiskowe a podpowłoki

Gdy uruchamiasz polecenie w podpowłoce (np. cmd /c polecenie), zmienne ustawione w tej podpowłoce nie wpływają na sesję macierzystą. Jest to częsta pułapka przy próbach modyfikacji zmiennych środowiskowych w pętlach lub przy wywoływaniu zewnętrznych narzędzi.

:: BŁĄD: podpowłoka nie zmienia zmiennej macierzystej
set MOJA_ZM=stara
cmd /c "set MOJA_ZM=nowa"
echo %MOJA_ZM%
stara (NIE zmieniona!)
:: POPRAWNIE: użyj polecenia w tej samej sesji
set MOJA_ZM=nowa
echo %MOJA_ZM%
nowa
:: Dla podpowłok: przekaż zmianę przez plik tymczasowy
cmd /c "set MOJA_ZM=nowa" > temp_env.bat
call temp_env.bat
del temp_env.bat
echo %MOJA_ZM%
nowa
14/14 13. Podsumowanie

Zmienne w systemie Windows i skryptach CMD stanowią fundamentalny mechanizm konfiguracji, przechowywania danych i komunikacji między komponentami systemu. Zrozumienie hierarchii zmiennych (systemowe, użytkownika, sesji), mechanizmów zasięgu (setlocal/endlocal), rozszerzenia opóźnionego oraz specjalnych technik jak przekazywanie wartości przez endlocal jest niezbędne dla każdego, kto zamierza pisać profesjonalne skrypty automatyzujące zadania administracyjne.

Pamiętaj o podstawowych zasadach: zawsze używaj setlocal na początku skryptów, stosuj rozszerzenie opóźnione (enabledelayedexpansion) przy manipulacji zmiennymi w pętlach i blokach warunkowych, chroń ścieżki z białymi znakami cudzysłowami, waliduj zmienne przed ich użyciem i stosuj konsekwentne nazewnictwo. Przestrzeganie tych zasad znacząco zwiększy niezawodność i czytelność Twoich skryptów.