Главная страница

Сам_себе_программист._Как_научиться_программировать_и_устроиться. Guide to Programming Professionally


Скачать 3.94 Mb.
НазваниеGuide to Programming Professionally
Дата25.02.2023
Размер3.94 Mb.
Формат файлаpdf
Имя файлаСам_себе_программист._Как_научиться_программировать_и_устроиться.pdf
ТипGuide
#954463
страница12 из 15
1   ...   7   8   9   10   11   12   13   14   15
Глава 18. Системы управления пакетами
Каждый программист — это автор.
Серкан Лейлек
Система управления пакетами (менеджер пакетов) — это программа, которая устанавливает другие программы и управляет ими. Она может быть полезна, по- скольку при создании нового программного обеспечения часто приходится поль- зоваться другими программами. Например, веб-разработчики часто используют веб-фреймворк — программу, позволяющую создать веб-сайт . Программисты исполь- зуют системы управления пакетами для установки веб-фреймворков и множества других программ. В этой главе вы научитесь использовать менеджер пакетов pip.
Пакеты
Пакет — это программное обеспечение , «упакованное» для распространения.
Пакет включает файлы, из которых собственно состоит программа, и метадан-
14
ru.wikipedia.org/wiki/ _ 

159
Введение в инструменты программирования
ные — информацию о данных вроде названия программного обеспечения, но- мера версии и зависимостей (программ, от которых зависит должная работа вашей программы). Для тог о чтобы загрузить и установить пакет на компьютер как программу, можно воспользоваться системой управления пакетами. Система управления пакетами управляет загрузкой всех зависимостей пакета.
Pip
В этом разделе я покажу вам, как использовать pip , менеджер пакетов для Python, чтобы загрузить пакеты Python. Как только вы загрузите пакет при помощи pip, вы сможете импортировать его в Python как модуль. Для начала проверьте, установлен ли pip на вашем компьютере, открыв bash (или командную строку
Windows) и введя команду pip.
bash_ex34.sh
$ pip
>> Usage: pip [options]
Commands:
install Install packages.
download Download packages. ...
После ввода команды должен отобразиться синтаксис команды с доступны- ми параметрами. Инструмент pip поставляется в комплекте с новыми версия- ми Python, но в ранних версиях он отсутствовал. Если после ввода команды pip ничего не происходит, значит, на вашем компьютере pip не установлен. Озна- комьтесь с инструкциями по его установке на сайте pythonworld.ru/osnovy/
pip.html.
Новый пакет можно установить при помощи команды pip install _
 . Pip устанавливает новые пакеты в папку site-packages в вашем каталоге
Python. Список всех доступных для загрузки пакетов Python вы можете найти на сайте pypi.python.org/pypi. Существуют два способа указать, какой пакет вы хотите загрузить, — указав только имя пакета, или имя пакета, за которым следуют два знака равенства (==) и желаемый номер версии. Если вы использу- ете только имя пакета, pip загрузит последнюю версию пакета. Второй вариант позволяет загрузить конкретную версию пакета вместо наиболее актуальной.
Ниже показано, как установить Flask, пакет Python для создания сайтов на
Ubuntu и Unix.
bash_ex35.sh
$ sudo pip install Flask==0.11.1
>>   :
>> Successfully installed  ask-0.11.1
В Windows вам нужно воспользоваться командной строкой от имени адми- нистратора. Щелкните правой кнопкой мыши по ярлыку инструмента команд-

160
Часть III
ной строки и выберите команду меню Запуск от имени администратора (Run as administrator).
В командной строке Windows введите следующее.
bash_ex36.sh
C:\Python36\Scripts\pip3.exe install Flask==0.11.1
>> Successfully installed  ask-0.11.1
При помощи этой команды pip устанавливает модуль Flask в папку
site-packages на вашем компьютере. Обратите внимание, что в вашем случае путь к файлу pip3.exe может быть иным!
Теперь можете импортировать модуль Flask в программу. Создайте новый файл Python, добавьте следующий код и запустите программу.
Python_ex283.py
1
from  ask import Flask
2
app
= Flask(__name__)
3
@app.route('/')
4
def index():
5
return ", !"
6
app.run(port
='8000')
>> * Running on http://127.0.0.1:8000/ (Press CTRL+C to quit)
Теперь в браузере перейдите по адресу http://127.0.0.1:8000/ — вы должны увидеть сайт с сообщением , !.
Модуль Flask позволяет быстро создать веб-сервер и веб-сайт. Посетите сайт flask.pocoo.org/docs/0.11/tutorial, чтобы узнать больше о том, как рабо- тает этот пример.
С помощью команды pip freeze можно просматривать перечень установ- ленных пакетов.

161
Введение в инструменты программирования
bash_ex37.sh
pip freeze
>> Flask==0.11.11
Наконец, программу можно удалить с помощью команды pip uninstall
_ . Удалите Flask следующей командой:
bash_ex38.sh
sudo pip uninstall  ask
>> Proceed (y/n)? y
Successfully uninstalled Flask-0.11.1
Теперь модуль Flask удален, в чем можно убедиться при помощи команды pip freeze
Виртуальные окружения
В конечном итоге вам захочется устанавливать пакеты Python в виртуальное
окружение вместо помещения в папку site-packages. Виртуальные окружения по- зволяют раздельно хранить пакеты Python для разных проектов. Чтобы узнать о виртуальных окружениях больше, перейдите по ссылке docs.pythonguide.org/
en/latest/dev/virtualenvs.
Словарь терминов
$PYTHONPATH
: Python ищет модули в списке папок, который хранится в пере- менной окружения $PYTHONPATH.
Apt-get: менеджер пакетов, который поставляется с Ubuntu.
Pip: менеджер пакетов для Python.
PyPI: веб-сайт, который содержит пакеты Python.
Site-packages: папка в $PYTHONPATH. Эта папка — место, куда pip устанавливает пакеты.
Веб-фреймворк: программа, помогающая создавать веб-сайты.
Виртуальное окружение: позволяет хранить пакеты Python для разных про- граммистских проектов раздельно.
Зависимости: программы, от которых зависит должная работа программы.
Метаданные: данные о данных.
Пакет: программное обеспечение, «упакованное» для распространения.
Система у правления пакетами (менеджер пакетов): программа, устанавливаю- щая другие программы и управляющая ими.
Практикум
Найдите пакет на PyPI (pypi.python.org) и загрузите его при помощи pip.
Решение: challenge_1.sh.

162
Часть III
Глава 19. Управление версиями
Я отказываюсь делать то, что могут сделать компьютеры.
Олин Шиверс
Создание программного обеспечения — командный вид спорта. Когда вы ра- ботаете над проектом совместно с другим человеком (или в команде), вам нужно вносить изменения в кодовую базу — папки и файлы, из которых формируется ваше программное обеспечение , — при этом, изменения должны быть синхро- низированы. Вы могли бы периодически слать друг другу электронные письма с изменениями и самостоятельно совмещать различные версии, но это было бы слишком утомительно.
Кроме того, что произойдет, если бы вы оба внесете изменения в одну и ту же часть проекта? Как решить, чьи изменения оставлять? Это именно те пробле- мы, которые решает система управления версиями. Система управления верси-
ями — это программа, разработанная с целью помогать вам без труда сотрудни- чать с другими программистами при работе над проектами.
Git и SVN — популярные системы управления версиями. Обычно система управления версиями используется в сочетании с сервисом облачного хранения.
В этой главе вы будете использовать Git, чтобы поместить программное обеспе- чение на GitHub , веб-сайт , хранящий код в облаке.
Репозитории
Репозиторий — это структура данных, созданная системой управления версия- ми, наподобие Git, которая отслеживает все изменения в программистском про- екте. Структура данных — это способ организовывать и хранить информацию: списки и словари являются примерами структур данных (вы узнаете больше о структурах данных в части IV). На вид репозиторий напоминает каталог с файла- ми внутри. Вы будете использовать Git, чтобы взаимодействовать со структурой данных, отслеживающей изменения в проекте.
При работе над проектом, управляемым Git, будет создано множество репо- зиториев (как правило, по одному на каждого человека, принимающего участие в работе). Обычно у каждого человека, который работает над проектом, на ком- пьютере есть репозиторий, называемый локальным репозиторием — он отсле- живает все изменения, которые этот человек вносит в проект. Также есть цен-
тральный репозиторий, размещенный на веб-сайте вроде GitHub , с которым обмениваются информацией все локальные репозитории, чтобы поддерживать синхронизацию друг с другом (каждый репозиторий полностью самостоятелен).
Программист, работающий над проектом, может обновлять центральный репо- зиторий согласно изменениям, которые он внес в свой локальный репозиторий, а также обновлять свой локальный репозиторий согласно последним изменени- ям, которые другие программисты внесли в центральный репозиторий. Если вы работаете над проектом с еще одним программистом, вся система будет выгля- деть следующим образом.

163
Введение в инструменты программирования
Вы можете создать новый центральный репозиторий на сайте GitHub (или из командной строки). Как только вы создадите центральный репозиторий, смо- жете использовать Git для создания локального репозитория, который будет об- мениваться с ним информацией.
Начинаем
Если GitHub изменит оформление сайта, инструкции в этом разделе также изме- нятся — в этом случае вы найдете новые инструкции на сайте www.codeschool.com/
learn/git. Для начала вам понадобится создать учетную запись GitHub на страни- це github.com/join. Чтобы создать на GitHub новый репозиторий, войдите в свою учетную запись GitHub (как только создадите ее) и щелкните по кнопке + в правом верхнем углу экрана. В появившемся меню выберите пункт New repository (Но- вый репозиторий). Присвойте репозиторию название hangman. Установите пе- реключатель в положение Public (Публичный) и установите флажок Initialize the
repository with a README (Инициализировать репозиторий с помощью README- файла). Теперь нажмите кнопку Create repository (Создать репозиторий).
Щелкните мышью по кнопке учетной записи в правом верхнем углу и выбе- рите пункт Your profile (Ваш профиль).
Вы увидите название своего репозитория — hangman. Щелкните по нему. Эта часть сайта — ваш центральный репозиторий. Видите кнопку Clone Or Download
(Клонировать или скачать)? Когда нажмете на нее, появится ссылка. Сохраните эту ссылку.
Прежде чем продолжить, нужно установить Git. Инструкции по установ- ке вы можете найти на сайте www.git-scm.com/book/en/v2/Getting-Started-
Installing-Git.
Центральный
репозиторий
Репозиторий
второго
программиста
Репозиторий
первого
программиста

164
Часть III
Как только вы установите Git, его можно будет использовать из командной строки. Введите в командной строке команду git.
bash_ex39.sh
$ git
>> usage: git [--version] [--help] [-C
] [-c name=value]
Если ваш вывод такой же, как в этом примере, значит, вы справились с уста- новкой Git.
Теперь при помощи команды git clone  __    мож- но загрузить локальный репозиторий на компьютер (используйте сохраненную ранее ссылку). Репозиторий будет загружен в тот каталог, из которого вы вы- полняете команду. Скопируйте ссылку или выберите команду Copy to clipboard
(Копировать в буфер обмена) и передайте ее в качестве параметра команде git clone
bash_ex40.sh
$ git clone
 __   
>>
Cloning into 'hangman'... remote: Counting objects: 3, done. remote: Total 3 (delta 0), reused 0 (delta 0), pack- reused 0 Unpacking objects: 100% (3/3), done. Checking connectivity... done.
Проверьте, загрузился ли локальный репозиторий с помощью ls.
bash_ex41.sh
$ ls
>> hangman
Должен отобразиться каталог hangman. Это ваш локальный репозиторий.
Помещение и извлечение данных
Прежде всего, с помощью Git вы сможете делать две вещи. Первая — обновлять свой центральный репозиторий, внося изменения из локального репозитория, то есть помещать данные (толкать). Вторая — обновлять свой локальный ре- позиторий, внося изменения из центрального репозитория, то есть получать
данные (тянуть).
Команда git remote –v (этот часто используемый флаг служит для вы- вода дополнительной информации) выводит URL-адрес центрального репо- зитория, в который ваш локальный репозиторий помещает данные и из ко- торого он их получает. Перейдите в свой каталог hangman и введите команду git remote

165
Введение в инструменты программирования
bash_ex42.sh
$ cd hangman
$ git remote -v
>> origin  _ _ B /hangman.git (fetch)
>> origin  _ _ B /hangman.git (push)
Первая строка вывода — это URL-адрес центрального репозитория, из кото- рого ваш проект будет получать данные , а вторая — URL-адрес центрального ре- позитория, в который ваш проект будет помещать данные. Скорее всего, в обоих случаях вы будете использовать один и тот же центральный репозиторий, поэто- му обе ссылки будут одинаковыми.
Пример помещения данных
В этом разделе вы внесете изменение в созданный вами и скопированный на компьютер локальный репозиторий hangman, а затем поместите это изменение в свой центральный репозиторий, размещенный на GitHub.
Переместите ваш файл Python с кодом из задания, выполненного вами в кон- це части I, в каталог hangman. Теперь в вашем локальном репозитории находится файл, не существующий в центральном репозитории — он не синхронизирован с вашим центральным репозиторием. Эту проблему можно решить, поместив в центральный репозиторий изменения, внесенные в локальный репозиторий.
Этот процесс состоит из трех шагов. Сначала вы индексируете файлы — со- общаете Git, какие измененные файлы вы хотите отправить в центральный ре- позиторий.
Команда git status отображает текущее состояние вашего проекта от- носительно вашего репозитория, чтобы вы могли решить, какие файлы индек- сировать. Эта команда выводит те файлы в локальном репозитории, которые отличаются от файлов в центральном репозитории. Когда файл не проиндекси- рован, он выделяется красным, когда проиндексирован — зеленым. Убедитесь, что вы находитесь внутри каталога hangman, и введите команду git status.
bash_ex43.sh
$ git status
>>
On branch master Your branch is up-to-date with 'origin/
master'. Untracked  les: (use "git add < le>..." to in- clude in what will be committed)
>> hangman.py
Файл hangman.py должен быть выделен красным. Проиндексировать файл можно при помощи команды git add .
bash_ex44.sh
$ git add hangman.py

166
Часть III
Теперь используйте команду git status, чтобы убедиться, что вы проин- дексировали файл.
bash_ex45.sh
$ git status
>>
On branch master Your branch is up-to-date with 'origin/
master'. Changes to be committed: (use "git reset HEAD
< le>..." to unstage)
new  le: hangman.py
Имя файла hangman.py теперь окрашено в зеленый цвет, поскольку вы про- индексировали его.
При помощи синтаксиса git reset _ _ вы можете отменить индексацию файла , не внося изменений в центральный репозиторий. Отмените индексацию файла hangman.py следующим образом.
bash_ex46.sh
$ git reset hangman.py
Убедитесь, что индексация была отменена с помощью команды git status.
>> On branch master Your branch is up-to-date with 'origin/
master'. Untracked  les: (use "git add < le>..." to include in what will be committed)
hangman.py
Повторно проиндексируйте файл.
bash_ex47.sh
$ git add hangman.py
$ git status
>>
On branch master Your branch is up-to-date with 'origin/
master'. Changes to be committed: (use "git reset HEAD
< le>..."to unstage)
new  le: hangman.py
Как только вы проиндексировали файлы, которые хотите поместить в цен- тральный репозиторий, можно приступать к следующему шагу, сохранению со-
стояния файлов — указанию Git записывать изменения, которые вы внесли в ло- кальный репозиторий. Это делается с помощью синтаксиса git commit -m
_! . Данная команда создает версию вашего проекта, сохраняе- мую Git. Флаг –m значит, что вы хотите добавить к состоянию сообщение, кото-

167
Введение в инструменты программирования рое поможет вам запомнить вносимые изменения и их причины (это сообще- ние похоже на комментарий). В качестве следующего шага вы поместите свои изменения в центральный репозиторий на GitHub, где и сможете увидеть свое сообщение.
bash_ex48.sh
$ git commit -m "      "
>> 1  le changed, 1 insertion(+) create mode 100644 hangman.py
Теперь все готово к последнему шагу. Вы можете внести изменения в свой центральный репозиторий с помощью команды git push origin master.
bash_ex49.sh
$ git push origin master
>>
1  le changed, 1 insertion(+) create mode 100644 hangman.
py Corys-MacBook-Pro:hangman coryalthoff$ git push ori- gin master Counting objects: 3, done. Delta compression using up to 4 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 306 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To https://
github.com/coryalthoff/hangman.git f5d44da..b0dab51 mas- ter -> master
После того как вы введете свои имя пользователя и пароль в командной стро- ке, программа git поместит измененные файлы на GitHub. Если на этом сайте вы взглянете на свой центральный репозиторий, то увидите файл hangman.py и добавленное к состоянию сообщение.
Пример извлечения данных
В этом разделе вы обновите свой локальный репозиторий, получив изменения из центрального репозитория. Вам нужно будет делать это всякий раз, как вы за- хотите обновить свой локальный репозиторий согласно изменениям, которые другой программист внес в центральный репозиторий.

168
Часть III
Отправляйтесь в свой центральный репозиторий, нажмите кнопку Create
new file (Создать новый файл). Создайте файл с именем new.py, а затем нажми- те кнопку Commit new file (Записать состояние нового файла). Этого файла еще нет в вашем локальном репозитории, так что локальный репозиторий не син- хронизирован с центральным. Вы можете обновить локальный репозиторий со- гласно изменениям в вашем центральном репозитории при помощи команды git pull origin master
bash_ex50.sh
$ git pull origin master
>> remote: Counting objects: 3, done. remote: Compressing objects: 100% (2/2), done. remote: Total 3 (delta 0), re- used 0 (delta 0), pack-reused 0 Unpacking objects: 100%
(3/3), done. From https://github.com/coryalthoff/hang- man b0dab51..8e032f5 master -> origin/master Updating b0dab51..8e032f5 Fast-forward new.py | 1 + 1  le changed,
1 insertion(+) create mode 100644 new.py
Git применил изменения в вашем центральном репозитории к локальному репозиторию. Файл new.py, который вы создали в центральном репозитории, те- перь должен находиться в локальном репозитории. Проверьте это с помощью команды ls.
$ ls
>> README.md hangman.py new.py
Откат версий
Git сохраняет ваш проект каждый раз, как вы сохраняете состояние файла. Вы можете откатиться к любому предыдущему состоянию — «отмотать назад» свой проект. К примеру, можно вернуть проект к состоянию, сделанному на прошлой неделе. Все ваши файлы и папки останутся такими же, какими они были на про- шлой неделе. Тогда вы можете перепрыгнуть к более свежему состоянию. У каж- дого состояния есть номер — уникальная последовательность символов, исполь- зуемая Git для идентификации состояния.
Вы можете просмотреть историю состояний вашего проекта с помощью ко- манды git log, выводящей все состояния.
bash_ex51.sh
$ git log
>> commit 8e032f54d383e5b7fc640a3686067ca14fa8b43f Author:
Cory Althoff Date: Thu Dec
8 16:20:03 2016 -0800

169
Введение в инструменты программирования
Create new.py commit b0dab51849965144d78de21002464dc0f9297fdc Author: Cory
Althoff Date: Thu Dec
8 16:12:10 2016 -0800
my  rst commit commit f5d44dab1418191f6c2bbfd4a2b2fcf74ef5a68f Author:
Cory Althoff Date: Thu Dec 8 15:53:25 2016 -0800 Initial commit
Вы должны увидеть три состояния. Первое относится к созданию центрально- го репозитория. Второе — к обновлению центрального репозитория при индекса- ции файла hangman.py. Третье — к созданию файла new.py. У каждого состояния есть номер. Вы можете изменить состояние вашего проекта, передав номер состояния в качестве параметра команде git checkout. Следующим кодом я мог бы отка- тить свой проект к тому состоянию, в котором он был, когда я впервые его создал: git checkout f5d44dab1418191f6c2bbfd4a2b2fcf74ef5a68f
Команда git diff
Команда git diff демонстрирует разницу между файлом в локальном и в цен- тральном репозитории. Создайте новый файл hello_world.py в локальном репози- тории и добавьте в него код print(", !").
Теперь проиндексируйте файл.
bash_ex52.sh
$ git add hello_world.py
Убедитесь, что все произошло должным образом.
bash_ex53.sh
$ git status
>>
Changes to be committed: (use "git reset HEAD < le>..." to unstage) new  le: hello_world.py
И сохраните состояние.
bash_ex54.sh
$ git commit -m "      ƒ  "
>>
1  le changed, 1 insertion(+) create mode 100644 hello_
world.py
Поместите свои изменения в центральный репозиторий.

170
Часть III
bash_ex55.sh
$ git push origin master
>>
Counting objects: 3, done. Delta compression using up to
4 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 383 bytes | 0 bytes/s, done. Total 3
(delta 0), reused 0 (delta 0) To https://github.com/co- ryalthoff/hangman.git 8e032f5..6f679b1 master -> master
Теперь добавьте в файл hello_world.py в локальном репозитории вторую стро- ку, print("!"). Этот файл отличается от файла в центральном репози- ториуме. Введите команду git diff, чтобы увидеть разницу.
bash_ex56.sh
$ git diff hello_world.py
>> diff --git a/hello_world.py b/hello_world.py index b376c99..83f9007 100644 --- a/hello_world.py +++ b/
hello_world.py -1 +1,2 print("Print, , !")
+print("!")
Git выделил код print("!") зеленым цветом шрифта, поскольку это новая строка кода. Оператор сложения (+) обозначает, что эта строка — но- вая. Если бы вы удалили код, удаленная часть была бы выделена красным цветом шрифта, и ей предшествовал бы оператор вычитания (-).
Дальнейшие шаги
В этой главе я описал возможности Git, которыми вы будете пользоваться чаще всего. Как только вы освоите базовые понятия, я советую посвятить время изу- чению продвинутых возможностей Git, таких как ветвление и слияние, на сайте
www.codeschool.com/learn/git.
Словарь терминов
Git: популярная система управления версиями.
GitHub: веб-сайт, хранящий код в облаке.
SVN: популярная система управления версиями.
Извлечение данных: обновление локального репозитория согласно изменени- ям в центральном репозитории.
Индексирование: указание Git, какие файлы (с изменениями) следует поме- стить в центральный репозиторий.
Кодовая база: папки и файлы, из которых формируется ваше программное обе- спечение.
Локальный репозиторий: репозиторий на вашем компьютере.
Номер состояния: уникальная последовательность символов, используемая Git для идентификации состояния.
Помещение данных: обновление центрального репозитория согласно измене- ниям в локальном репозитории.

171
Введение в инструменты программирования
Репозиторий: структура данных, созданная системой управления версиями, на- подобие Git, которая отслеживает все изменения в вашем программистском про- екте.
Система управления версиями: программа, разработанная с целью помогать вам без труда работать над проектами совместно с другими программистами.
Состояние: версия вашего проекта, сохраняемая Git.
Сохранение состояния: написание команды, указывающей Git записывать из- менения, которые вы внесли в свой репозиторий.
Структура данных: способ организовывать и хранить информацию. Списки и словари являются примерами структур данных.
Центральный репозиторий: репозиторий, размещенный на веб-сайте вроде
GitHub, с которым обмениваются информацией все локальные репозитории для поддержания синхронизации друг с другом.
Практикум
Создайте новый репозиторий на GitHub. Переместите все ваши файлы Python из ранее выполненных заданий в один каталог на компьютере и поместите их в ваш новый репозиторий.
Глава 20. Практикум. Часть III
В наше время осуществилось волшебство мифа и легенды.
С клавиатуры вводится верное заклинание, и экран монитора оживает,
показывая то, чего никогда не было и не могло быть.
Фредерик Брукс
В этой главе вы увидите, насколько мощным является программирование, соз- дав парсер веб-контента — программу, которая извлекает данные с веб-сайта .
Когда вы создадите парсер контента, вы получите возможность собирать дан- ные из самого объемного информационного хран илища, когда-либо существо- вавшего. Мощь парсеров контента, а также простота их создания являются од- ной из причин, по которым я подсел на программирование, надеюсь, на вас это произведет аналогичный эффект.
HTML
Прежде чем приступать к созданию парсера контента, позвольте мне быстро ввести вас в курс дела насчет HTML — языка гипертекстовой разметки (англ. hypertext markup language). Наряду с CSS и JavaScript, язык HTML является од- ной из фундаментальных технологий, с помощью которых программисты стро- ят веб-сайты. HTML — язык, который создает структуру сайта, он состоит из
HTML-элементов, используемых браузером для создания макетов веб-страниц.
Вы можете построить целый сайт при помощи HTML, и хотя он не будет инте- рактивным и не будет приятно выглядеть из-за того, что за интерактивность от- вечает JavaScript, а за стиль — CSS, это все равно будет настоящий веб-сайт. Ниже показан сайт, который отображает текст , !.

172
Часть III
bash_ex57.sh
% G    ƒ    index.html-->
1   ...   7   8   9   10   11   12   13   14   15


написать администратору сайта