Dlaczego Python w Linuksie wymaga wiersza #! / Usr / bin / python?


50

Całkiem proste pytanie: w systemie Linux, dlaczego Python wymaga linii

#!/usr/bin/python

na początku pliku python, ponieważ Windows nie?

Co to robi? ponieważ opis „Linki do Pythona” jest nieco niejasny ...


28
Wszystkie poniższe odpowiedzi są poprawne, żadna z nich nie wyjaśnia, dlaczego system Windows nie potrzebuje tej linii. System Windows zależy od rozszerzenia pliku (część po .), aby określić, jaki to plik. Nawet Windows odchodzi od tego: sprawdź kilka pierwszych wierszy pliku Microsoft Word, a stwierdzi, że w rzeczywistości jest to plik Microsoft Word.
Charles Green,

9
Słoniem w pokoju jest to, że NIGDY nie powinieneś używać / usr / bin / python, chyba że jesteś kompatybilny z python 2 i 3. Powód: arch dowiązuje go do python3, co zostało potwierdzone przez PSF, który sam go poleca.
Yet Another User

5
Sugeruje się, ale nie podano wprost w odpowiedziach poniżej, że nie jest to wymagane . Jest to wymagane, jeśli chcesz wykonać skrypt tylko z własnej nazwy. Zawsze możesz python myscript.pyzamiast tego uruchomić .
Chris H

3
@CharlesGreen nie powinniśmy wiedzieć, dlaczego Windows nie ;-) To zależy od SO.
Rinzwind

2
@YetAnotherUser Minęło sześć lat i jedenaście miesięcy od wydania Pythona 3, w tym momencie wydaje mi się, że lepiej byłoby, gdyby domyślnie używano 3 i wyraźnie określano użycie 2, jeśli to konieczne.
JAB

Odpowiedzi:


58

Python nie ma takich specjalnych wymagań w systemie Linux. Jest to program ładujący w systemie Unix / Linux, który używa linii „shebang”, jak się nazywa. To właściwie funkcja, a nie ograniczenie, ale przejdziemy do tego za chwilę. Strona Wiki w „shebang” zawiera więcej szczegółów, ale postaram się tutaj przedstawić przegląd, a także porównanie z Windows.

Najpierw spójrzmy na sytuację w systemie Windows:

  • Podczas próby otwarcia lub uruchomienia pliku system Windows najpierw sprawdza rozszerzenie tego pliku. Jest to ostatnia część nazwy pliku rozpoczynająca się od. .W przypadku plików Python jest to zwykle .py.
  • System Windows sprawdza, jakie działania należy podjąć na podstawie rozszerzenia pliku.
    • Informacje te są rejestrowane w rejestrze systemu Windows; kiedy Python jest zainstalowany, zazwyczaj mówi Windowsowi, że .pypliki powinny być otwierane przy użyciu nowo zainstalowanej aplikacji Python (tj. interpretera Python).
    • Kilka typów plików ma wbudowane zachowania; na przykład pliki wykonywalne (takie jak sam interpreter Pythona) muszą kończyć się .exe, a .batpliki są wykonywane jako skrypty wsadowe systemu Windows.
    • Czynność podjęta dla określonego typu pliku można dostosować . Możesz na przykład powiedzieć systemowi Windows, że zamiast uruchamiać .pypliki przy użyciu python.exe, powinien otworzyć je za pomocą innego programu, takiego jak edytor tekstu notepad.exe.
      • W takim przypadku, aby uruchomić skrypt w języku Python, musisz ręcznie wywołać python <scriptname>.py(lub napisać .batplik, aby to zrobić).

Co się stanie, jeśli na górze skryptu Python znajduje się linia shebang ( #!/usr/bin/pythonlub #!/usr/bin/env python)? Cóż, ponieważ #w Pythonie jest wiersz komentarza, interpreter języka Python po prostu go ignoruje. Jest to jeden z powodów, dla których większość języków skryptowych używanych w świecie Unix / Linux używa #linii komentarza.

Więc trochę mylące jest stwierdzenie, że Windows „nie potrzebuje” #!linii; Windows nie zobaczyć ten #!wiersz, a w rzeczywistości opiera się na pliku-extension, aby powiedzieć jej, co zrobić. Ma to kilka wad:

  • Na końcu musisz nazwać skrypty Pythona .py, aby były automatycznie rozpoznawane jako takie.
  • Nie ma łatwego sposobu na odróżnienie skryptów Python2 od skryptów Python3.
  • Jak wspomniano wcześniej, jeśli zmienisz domyślne zachowanie uruchamiania dla typu .pypliku, system Windows nie będzie już automatycznie uruchamiał tych skryptów w języku Python. Pamiętaj, że można to zrobić przypadkowo.

Spójrzmy teraz, jak Unix / Linux uruchamia skrypty:

Pierwszą rzeczą, na którą należy zwrócić uwagę, jest to, że Unix / Linux, w przeciwieństwie do systemu Windows, nie próbuje „otwierać” skryptów Pythona przy użyciu określonego programu, przynajmniej koncepcyjnie; system operacyjny wie, że skrypt jest czymś, co można wykonać z powodu czegoś, co nazywa się „bitem wykonania” (co jest poza zakresem tej odpowiedzi). Jeśli przypadkowo wpiszesz #!/usr/bin/pthonzamiast #!/usr/bin/python, pojawi się komunikat o błędzie zawierający ten tekst:

/usr/bin/pthon: bad interpreter: No such file or directory.

Słowo „tłumacz” daje nam wskazówkę dotyczącą roli linii shebang (choć technicznie określony program może być czymś innym niż tłumacz, np. catEdytor tekstu). Podczas próby uruchomienia pliku, oto co się dzieje:

  • Program ładujący dla systemów Unix / Linux sprawdza pierwsze dwa bajty tego pliku; jeśli są to dwa bajty #!, moduł ładujący interpretuje pozostałą część linii shebang (z wyłączeniem samego shebang) jako polecenie uruchomienia interpretera, za pomocą którego można uruchomić zawartość pliku jako skrypt.
  • Program ładujący uruchamia określony interpreter, podając mu ścieżkę oryginalnego pliku jako argument.

Ma to kilka zalet:

  • Autor skryptów ma większą kontrolę nad tym, który interpreter będzie używany (co rozwiązuje problem Python2 / Python3) i czasami może przekazać dodatkowy argument do interpretera (szczegóły na stronie Wiki).
  • Nazwa pliku skryptu jest ignorowana , więc możesz nazywać skrypty Python, jak chcesz.

Na koniec zauważ, że Unix / Linux nie potrzebuje linii shebang, aby uruchomić skrypt w Pythonie. Przypomnij sobie, że tak naprawdę cała linia shebang pozwala programowi ładującemu wybrać tłumacza. Ale podobnie jak w systemie Windows można to zrobić ręcznie:

python <myscript>

1
W systemie Windows można łatwo mieć .py2i .py3rozszerzenia dla Python / Python 2 3 skrypty. Więc zarówno Linux (+ x bit), jak i Windows (rozszerzenie pliku) potrzebują metadanych w systemie plików. Główną różnicą jest to, że bit + x łatwiej jest zgubić podczas transportu. To niekoniecznie jest wadą.
MSalters

1
@MSalters Bit wykonawczy zawiera również o wiele mniej zakodowanych informacji. I zauważ, że możesz mieć wielu interpreterów języka Python2 w danym systemie (podobna sytuacja była z Ruby i innymi językami na moim poprzednim zadaniu); radzenie sobie z tym za pomocą linii shebang jest prawie banalne, podczas gdy sytuacja w systemie Windows staje się znacznie trudniejsza do rozwiązania, im więcej próbujesz zarządzać wieloma podobnymi typami plików.
Kyle Strand,

Ponadto, czy rozszerzenie naprawdę liczy się jako „metadane”? To tylko część nazwy pliku.
Kyle Strand,

1
Metadane pliku obejmują całą nazwę pliku, czas utworzenia, bity dostępu itp. Tylko sama treść to dane zamiast metadanych. Jeśli chodzi o „wielu tłumaczy”, to rzeczywiście jest prawdziwy problem i właśnie dlatego nie powinien znajdować się w linii shebang. Co jeśli masz /usr/bin/i686/pythoni /usr/bin/amd64/python? Idealnie rozsądne, ale łamie skrypty pythonowe, które mają zakodowane założenia /usr/bin/python. Wybór tłumacza nie jest wyborem pisarza skryptu, ale użytkownika skryptu, pisarz może jedynie wybrać język (dialekt).
MSalters

1
@MSalters Cóż, po to właśnie /usr/bin/envjest, wraz ze skryptami konfiguracji env. Jaka jest wersja tego systemu Windows? Uruchamianie regeditskryptu tuż przed uruchomieniem .pypliku, aby upewnić się, że masz tłumacza, którego potrzebujesz?
Kyle Strand,

41

Wskazany wiersz służy do informowania komputera, jakiego programu / interpretera należy użyć podczas bezpośredniego uruchamiania pliku / skryptu oraz wszelkich argumentów, które należy przekazać temu programowi podczas działania skryptu. Nie jest to jednak wymagane przez Python , jest to wymaganie jądra / systemu Linux, jeśli zamierzasz uruchomić skrypt bezpośrednio (i nie przekazać go do Pythona zgodnie z poniższą składnią).

Nie jest to konieczne, jeśli zamierzasz wykonać python script.pylub podobnie. Jest to potrzebne tylko wtedy, gdy zamierzasz uruchomić skrypt / plik bezpośrednio, nie udostępniając również interpretera (takiego jak python).


W przypadku skryptu Bash miałby coś takiego:

#!/bin/bash [optional Bash arguments]
# Bash script code here
...
exit 0;

Oznaczałoby to systemowi, że po uruchomieniu powinien zostać uruchomiony przez /bin/bashjeden z języków powłoki / skryptów powłoki w systemie.


Jednak w przypadku kodu Python tutaj będziesz chciał, aby plik wykonywalny był uruchamiany przez Python, więc powiedz mu, jaki interpreter zamierzasz w nim uruchomić.

#!/usr/bin/python [optional Python arguments]
# Python code here
...
exit()

To, podobnie jak w przypadku Bash, wskazuje, że /usr/bin/pythonnależy go użyć (prawdopodobnie jest to Python 2 lub Python 3, w zależności od indywidualnych konfiguracji systemu).


W ten sposób, można uruchomić ./filename.pylub ./executablelub ./scripttorunbezpośrednio.

Bez tej linii na początku i zakładając, że ustawiłeś plik / skrypt, aby był wykonywalny, i zakładając, że pracujesz ze skryptem Pythona, musiałbyś uruchomić python filename.pylub podobnie, gdyby nie miał #!/usr/bin/pythonlinii. (W przypadku skryptu Bash trzeba to zrobić bash script.shlub podobnie w przypadku innych skryptów / języków, takich jak Perl, Ruby itp.)

Podświetlanie składni powyżej jest specyficzne dla języka w każdej sekcji, chociaż tak naprawdę nie ma znaczenia.


1
Ciekawą rzeczą byłoby dodać, że jest to możliwe, aby określić dodatkowe parametry po samej shebang, w większości przypadków w taki sam sposób, jak gdyby interpreter nazwano bezpośrednio ( #!/bin/bash -x, #!/usr/bin/perl -lanitp).
Kos

7
@kos: Myślę, że możesz podać dokładnie jeden dodatkowy argument, który był PITA, kiedy należy (należy) użyć, /usr/bin/env pythonaby uzyskać poprawny python.
unperson325680,

@progo Nie jestem pewien, z czym jest problem env, ale wydaje się, że problemem nie jest liczba argumentów: #!/usr/bin/perl -l -a -nma trzy argumenty, ale działa. Chociaż znowu nie jestem w stanie zrozumieć dokładnego problemu.
Kos

Podczas jawnego wywoływania interpretera ze skryptem jako argumentem, nie ma powodu, aby ten ostatni zaczynał ./. Innymi słowy, po prostu python filename.pylub bash script.shbędzie działać dobrze. Jedynym powodem do włączenia ./jest nazwa polecenia, gdy chcesz powiedzieć powłoce, by nie wyszukiwała $PATH(co prawdopodobnie nie znajdzie plików w bieżącym katalogu), ale podążyła ścieżką podaną w niezmienionej postaci. Ale to nie dotyczy argumentów poleceń.
Marc van Leeuwen,

@kos: Problemem może być sposób envodbierania pozostałych argumentów z jądra. Można przypuszczać, że wszystkie są jednym wielkim argumentem bez podziału na miejsca. Przepraszam za artykulację, już nie pamiętam szczegółów tego
unperson325680

16

Linia:

#!/usr/bin/python

nazywa się „shebang” i wskazuje ścieżkę do pliku binarnego interpretera, który zostanie użyty do zinterpretowania pozostałych poleceń w pliku. Zazwyczaj jest to pierwszy wiersz skryptu.

Zatem linia #!/usr/bin/pythonwskazuje, że zawartość pliku będzie interpretowana przez pythonplik binarny zlokalizowany w /usr/bin/python.

Zauważ, że linia shebang jest analizowana przez jądro, a następnie skrypt zostanie ostatecznie wywołany jako argument:

python script_name

Podobnie w przypadku #!/bin/bash:

bash script_name

2
Nie sądzę, żebym kiedykolwiek widział łącznik shebang. Ponieważ słowo składa się z „mieszania” i „huku”, pisownia nie jest zbyt wyraźna, ponieważ wygląda na połączenie „ona” i „huk”.
Kyle Strand,

Możesz go nazwać hashbang( #= „skrót”) lub shebang( #= „ostry”), w zależności od tego, jak nazwiesz #znak. Jednak shebangrzeczywiście jest bardziej powszechny. @KyleStrand
Byte Commander

7

Technicznie nie wymaga tego. Wymaga ścieżki do środowiska, w którym wykonuje się skrypt. Przyszłe skrypty lepiej byłoby dołączyć / usr / bin / env, a następnie określić python. Zapewnia to, że twój skrypt działa w środowisku Pythona bez względu na to, gdzie jest zainstalowany Python. Chcesz to zrobić ze względu na kompatybilność, nie możesz być pewien, że następna osoba, której udostępnisz swój kod, będzie miała zainstalowanego Pythona w usr / bin / python lub że będzie miała uprawnienia do tych plików systemowych.

Oto podobne pytania i odpowiedzi dotyczące przepełnienia stosu .

W skrypcie wygląda to tak:

#!/usr/bin/env python

Widzę także pewne obawy dotyczące sposobu określania python3. Oto jak to zrobić:

#!/usr/bin/env python3

5

W Linuksie Python może, ale nie musi, wymagać #!wiersza (shebang). Zależy to od tego, jak obsługiwane są kody w języku Python, uruchamiając je w trybie interaktywnym lub w skrypcie w języku Python.

Tryb interaktywny w języku Python pozwala użytkownikowi pisać i uruchamiać kody w języku Python bezpośrednio, co nie wymaga linii shebang. Aby uruchomić tryb interaktywny, otwórz terminal i wpisz pythonPython 2.X lub python3Python 3.X.

$  python
Python 2.7.6 (default, Jun 22 2015, 18:00:18) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 

$  python3
Python 3.4.3 (default, Oct 14 2015, 20:33:09) 
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

Skrypt w języku Python pozwala użytkownikowi pisać i zapisywać kody w języku Python w zwykłym pliku tekstowym, a następnie uruchamiać je później. Może to wymagać linii shebang lub nie. Istnieją jednak dwa znane powody, dla których linia shebang jest wymagana do używania skryptu Python w systemie Linux.

  1. uruchamiać kody Pythona w skrypcie wykonywalnym, tj. określa sposób uruchamiania kodów i użycie interpretera;

  2. uruchamiać kody Pythona w odniesieniu do konkretnej wersji Pythona, tj. uruchamiać kody, które są kompatybilne tylko z Python 2.X lub Python 3.X

Ćwicz ze skryptami Python

Poniżej znajduje się lista i zawartość plików, których użyłem, aby pokazać przypadki, że #!linia (shebang) jest wymagana lub nie jest wymagana.

$  ls -ln *.py
-rw-rw-r-- 1 1000 1000  94 Dec 14 18:37 hello1.py
-rwxrwxr-x 1 1000 1000 116 Dec 14 18:37 hello2e.py
-rw-rw-r-- 1 1000 1000 116 Dec 14 18:37 hello2.py
-rwxrwxr-x 1 1000 1000 117 Dec 14 18:37 hello3e.py
-rwxrwxr-x 1 1000 1000 120 Dec 14 18:37 hello3m.py
-rw-rw-r-- 1 1000 1000 117 Dec 14 18:37 hello3.py

$  file *.py
hello1.py:  ASCII text
hello2e.py: Python script, ASCII text executable
hello2.py:  Python script, ASCII text executable
hello3e.py: Python script, ASCII text executable
hello3m.py: Python script, UTF-8 Unicode (with BOM) text executable
hello3.py:  Python script, ASCII text executable
  • hello1.py zawiera tylko kod źródłowy.

    import sys
    sys.stdout.write("Hello from Python %s\n" % (sys.version,))
    print("Hello, World!")
    
  • hello2.py zawiera kod źródłowy i linię shebang.

    #!/usr/bin/env python
    import sys
    sys.stdout.write("Hello from Python %s\n" % (sys.version,))
    print("Hello, World!")
    
  • hello2e.pyzawiera to samo co hello2.pyi wykonane.

  • hello3.pyzawiera to samo co hello2.py, z tym wyjątkiem, że jest przystosowany do działania z Pythonem 3 przez zmianę nazwy pierwszego wiersza na #!/usr/bin/env python3.

  • hello3e.pyzawiera to samo co hello3.pyi wykonane.

  • hello3m.pyzawiera takie same hello3.pyi wykonane jako wykonane, z wyjątkiem tego, że zapisano je z Write Unicode BOMopcją w edytorze tekstu, tj. podkładką pod mysz.

Poza tym użytkownikowi zostaną przedstawione dwie metody uruchamiania skryptów w języku Python. Obie metody zostały przedstawione poniżej.

Metoda 1: Uruchom z programem Python

Poniżej znajdują się polecenia i dane wyjściowe podczas uruchamiania kodu źródłowego w Pythonie 2 i Pythonie 3.

$  python hello1.py
Hello from Python 2.7.6 (default, Jun 22 2015, 18:00:18) 
[GCC 4.8.2]
Hello, World!

$  python3 hello1.py
Hello from Python 3.4.3 (default, Oct 14 2015, 20:33:09) 
[GCC 4.8.4]
Hello, World!

Obie wersje Pythona mogły pomyślnie uruchomić skrypt. W związku z tym linia shebang nie jest wymagana podczas uruchamiania skryptu Python za pomocą polecenia pythonlub python3.

Metoda 2: Uruchom jako skrypt w języku Python

Poniżej znajdują się polecenia i dane wyjściowe podczas uruchamiania kodu źródłowego z linią shebang, które nie są dostosowane do żadnego z nich, Python 2 i Python 3, w tym przypadków niewykonywalnych i wykonywalnych.

$  ./hello1.py
bash: ./hello1.py: Permission denied

$  ./hello2.py
bash: ./hello2.py: Permission denied

$  ./hello3.py
bash: ./hello3.py: Permission denied

$  ./hello2e.py 
Hello from Python 2.7.6 (default, Jun 22 2015, 18:00:18) 
[GCC 4.8.2]
Hello, World!

$  ./hello3e.py 
Hello from Python 3.4.3 (default, Oct 14 2015, 20:33:09) 
[GCC 4.8.4]
Hello, World!

Pierwsze trzy skrypty zakończyły się niepowodzeniem, ponieważ skrypty te nie są wykonywane, niezależnie od tego, czy mają linię shebang, czy nie (Aby uzyskać dowód, patrz Dodatkowy przykład poniżej). Ostatnie dwa skrypty mają linię shebang i są wykonywalne.

Najwyraźniej skrypt, który został wykonany jako wykonywalny, jest w zasadzie bezużyteczny bez linii shebang. Dlatego wymagana jest linia shebang, a skrypt musi być wykonywalny podczas uruchamiania kodów Python w skrypcie wykonywalnym.

Gdy shebang nie działa

W moim przygotowanym i przetestowanym przykładzie działanie hello3m.pyjako skrypt wykonywalny nie powiodło się i zwróciło błąd.

$  ./hello3m.py 
./hello3m.py: line 1: #!/usr/bin/env: No such file or directory

Jest to znane ograniczenie, że shebang nie działa lub staje się nieważny. Kiedy plik zostanie zapisany jako Unicode BOM (Byte Order Mark), nie będzie działał normalnie jako wykonywalny skrypt Pythona.

Dodatkowy przykład

Ten dodatkowy przykład należy traktować wyłącznie jako dowód uzupełniający. Użytkownik powinien unikać uruchamiania tego przykładu, chociaż wynik jest nieszkodliwy.

Utworzyłem inny plik o nazwie hello1e.py, który zawiera ten sam hello1.pyplik i jest wykonywalny. Uruchomienie tego skryptu zwróciło błąd składniowy.

$  ./hello1e.py 
./hello1e.py: line 2: syntax error near unexpected token `"Hello from Python %s\n"'
./hello1e.py: line 2: `sys.stdout.write("Hello from Python %s\n" % (sys.version,))'

Podczas uruchamiania tego skryptu kursor myszy zostanie na początku zmieniony na znak plus i nic nie robi. Błąd składniowy nie będzie wyświetlany, dopóki nie kliknę okna Desktop lub Terminal. Następnie ten skrypt utworzy sysplik w tym samym katalogu co skrypt.

$  file sys
sys: PostScript document text conforming DSC level 3.0, Level 1

sysPlik został zidentyfikowany jako plik PostScript, bez rozszerzenia pliku. Ten plik można otworzyć w przeglądarce dokumentów, tj. Evince, a plik faktycznie zawiera zrzut ekranu okna, które kliknąłem wcześniej. Z mojego doświadczenia wynika, że ​​plik może mieć wielkość kilku megabajtów.

Ponownie wymagana jest linia shebang, a skrypt musi być wykonywalny podczas uruchamiania skryptu Python jako skryptu wykonywalnego. W przeciwnym razie skrypt będzie źle działał, jak opisano powyżej.

Dodatkowe uwagi

Termin „wykonywalny” lub „musi być wykonywalny” odnosi się do pozwolenia na uruchomienie skryptu. Odbywa się to poprzez uruchomienie chmod +x FILENAMEpolecenia w Terminalu lub zaznaczenie opcji „Zezwól na uruchamianie tego pliku jako programu” lub czegoś podobnego w oknie Właściwości w menedżerze plików.

Podczas gdy inne istniejące odpowiedzi obejmowały prawie wszystko, ta odpowiedź przyjęła inne podejście, wykorzystując praktyczne przykłady w celu wyjaśnienia sprawy. Składnia kodu została napisana z ostrożnością, tak aby przykłady mogły być uruchamiane w Pythonie 2 lub Pythonie 3, tak jak jest.

Kody Pythona zostały zaadaptowane z używania Pythona w systemie Windows i używania Pythona na platformach Unix , z dodatkowym jednuliniowym kodem wszechobecnego „Hello, World!” program.

Wszystkie kody i polecenia zostały w pełni przetestowane i działają w systemie Xubuntu 14.04, w którym domyślnie zainstalowano Python 2.7 i Python 3.4.


4

Oznacza to, że po uruchomieniu tego pliku komputer wie, jak go uruchomić z programem /usr/bin/python, tak odróżniasz go od innego języka, takiego jak bash, gdzie byś to zrobił #!/bin/bash. Dzięki temu możesz po prostu uruchomić:

./[file-to-execute]

Będzie wiedział, z którym plikiem go wykonać, a nie ty sam musisz określić za pomocą czegoś takiego:

python ./[file-to-execute].py

Ta #!część jest powszechnie określana jako shebang lub crunch bang .


2
Również hashbang.
Naftuli Kay

1

Jeśli masz zainstalowanych kilka wersji Pythona, /usr/bin/envupewnij się, że używany interpreter jest pierwszym w twoim środowisku $PATH. Alternatywą byłoby hardcode coś takiego #!/usr/bin/python;

W Uniksie plik wykonywalny, który ma być interpretowany, może wskazywać, jakiego interpretera użyć, umieszczając #!na początku pierwszego wiersza, a za nim interpreter (i wszelkie potrzebne flagi).

Ta reguła dotyczy tylko systemu UNIX.


0

przydatne dla systemów operacyjnych takich jak Linux, gdzie Python 2.x jest nadal standardem, ale większość ludzi pobiera również 3.x.

2.x działałby domyślnie. Więc mój kod 3.x, poprzedzam #! / Usr / bin / env python3, aby 3.x uruchomił kod. Mogę nawet sprowadzić do drobnej wersji (python 3.xyz), jeśli wybrałem wersje beta lub nieco starsze wersje.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.