Kodomo

Пользователь

Основы командной строки UNIX

Большая часть работы с веб у нас будет происходить на сервере web-corpora.net, который работает под управлением ОС UNIX, и нам бы неплохо научиться этой ОС управлять.

Для начала нам потребуется:

Открываем PuTTY, вводим адрес web-corpora.net, остальное оставляем как есть, попадаем на сервер. Тут мы можем давать ему команды и видеть ответы.

Как ходить и смотреть

Посмотрим, какие есть файлы там, где мы сейчас:

ls

никаких? Тогда попросим показать и скрытые файлы тоже. (В командной строке UNIX команды отделяются от аргументов пробелами и разные аргументы тоже отделяются друг от друга пробелами).

ls -a

Вывод: в UNIX скрытые файлы это те файлы, имя которых начинается с точки.

Среди прочих скрытых файлов видим две папочки: . и ..

И вспомним, что ещё мы знаем про пути:

Узнать, где мы находимся, можно командой pwd (print working directory)

pwd

Перейти в другое место можно командой cd (change working directory – на заре UNIX клавиатуры были очень жёсткие, и когда Денниса Ритчи спросили, что бы он изменил в UNIX, если бы сочинял его заново, он ответил: переименовал бы creat в c).

cd dirname
pwd
ls
cd ..
pwd
ls
cd /tmp
pwd
ls
cd ../home
pwd
ls

/tmp – это специальная папка, являющаяся всеобщей свалкой всего временного. Она периодически очищается, и вы не имеете над этим власти. Не кладите туда ничего ценного. И убирайте там за собой, если вы что-нибудь вы туда положили (а то и вправду воняет).

Когда мы загуляли куда-то далеко, очень хочется телепортироваться домой. Для этого есть специальное сокращение:

cd

Без аргументов она переносит нас домой.

Как наводить порядок: создавать, удалять и переименовывать

Теперь будем учиться организовывать своё рабочее пространство: создавать, удалять, переименовыать.

mkdir dirname

Так и расшифровывается: make directory. (В смысле, создать)

rmdir dirname

Remove directory – пояснений не требует.

Теперь мы хотим создать файл с каким-нибудь наполнением. Текстовые редакторы в UNIX не очень удобные, так что их не трогаем. Зато очень легко сохранить в файл выдачу команды, например, ls:

ls > file_list

Оператор перенаправления > говорит, что на экран ничего не попадёт, зато вся выдача программы будет сохранена в файл с именем, которое мы дали. (В данном случае file_list).

Некоторые программы умеют замечать, что их таким образом подслушивают, и выдавать в файл другое содержимое, чем на экран. ls, например, в файл пишет список файлов по одному в столбик, чтобы с ними было удобно раборать программам, а на экран форматирует их покучнее и почитаемее.

Теперь мы умеем создавать файлики и их можно подвигать взад-вперёд:

mkdir stuff
mv file_list stuff
ls
ls stuff

mv от слова move, имеет такие аргументы: mv что что что... куда

создадим ещё файликов:

cd stuff
ls > stuff_file_list
ls
pwd

Теперь хочется сделать что-нибудь с кучей файликов. Для этого в качестве частей аргументов команд можно использовать такие выражения (они называются glob или wildcard):

NB: это совсем не регулряные выражения, это сильно более простые шаблоны, возможности их гораздо более ограничены, и смысл символов в них другой.

Чтобы поиграться с шаблонами нам полезно знать, что ls -d не показывает содержимое папки, а показывает только список папок, которые мы ему дали:

ls -d
ls -d /???
ls -d *
ls -d a*
ls -d /[a-n]*

Как смотреть содержимое

Вернёмся к нашим файлам:

cd
cd stuff

Мы хотим посмотреть их содержимое. В UNIX особо богаты средства работы с текстами. (Да и вообще, идеология UNIX предполагает, что всё в операционной системе должно быть текстом). Поэтому в нём безумное количество возможностей обрабатывать, преобразовывать и выводить текст на экран. Расскажу только две самые простые.

cat file_list

Утилита cat тупо выводит файл на экран. Она очень тупая. Она не ждёт, пока вы прочитаете страницу, а вываливает его целиком. Если файл очень большой, то выводиться на экран он будет очень долго.

Но для маленьких файлов удобно.

Если ей дать несколько аргументов, она склеит файлы вместе:

cat * > new_file

В честь этого она и названа: conCATenate.

А если мы хотим удобств, нормальной работы со сколь-угодно большими файлами, возможности поиска, нормальной работы со стрелочками и пр, возможности делать закладки и прыгать через них, возможности открывать несколько файлов и переключаться между ними, то для этого существует просмотрщик less:

less new_file

Два главных знания про less:

Хелпы

И самая главная команда UNIX:

man ls

от слова manual (тот manual, который мануал или пользовательское руководство, а не другие manual). Она знает хелпы почти про что угодно и показывает их с помощью less.

Teaser

Ну и напоследок пример на тему того, что можно делать в UNIX за счёт его вопиюще-текстовой природы. UNIX не умеет делать такое дело, как считать, сколько файлов с каким расширением находится в данной папке, да ещё и игнорируя файлы в подпапках .svn где-либо. Однако, команду, которая это умеет делать, очень несложно сочинить, выглядеть она будет, например, так:

find | fgrep -v '.ssh' | sed -r 's/.*([.][^.]*$)/\1/' | sort | uniq -c | sort -n | tail

Здесь нет ничего сложного. Достаточно знания полутора десятка команд, парочки параметров для некоторых из них, регулярных выражений и ещё двух-трёх элементов синтаксиса командной строки UNIX, – и вы сможете писать так же. В итоге многие часто возникающие в жизни компьютерного лингвиста технические задачи массовой обработки данных можно решать неделями вручную, за пару часов, написав скрипт на питоне, или за пять-десять минут, составив вот такого рода конструкцию. (Я почти всегда из этих вариантов предпочитаю последний).

Эта тема в плане называется "Основы UNIX для обработки текстов".

Flask: адреса, шаблоны, переменные

Подготовка рабочего места.

Либо можете работать на нашем сервере: web-corpora.net

В прошлый раз мы написали такую программку, которая отвечает на все запросы "покажи мне страницу" словами "404 ошиблись адресом":

   1 from flask import Flask
   2 
   3 app = Flask(__name__)
   4 
   5 if __name__ == "__main__":
   6     app.run(host='0.0.0.0', port=2020)

В качестве параметра port мы даём ей номер порта, которым мы будем пользоваться. Так как две программы не могут принимать соединения с одним и тем же номером порта (ведь номер порта и есть идентификатор программы), то нам нужно всем пользоваться разными номерами. Чтобы не ссориться, я записал в ведомость колонку "порт" и присвоил каждому его номер порта. Выучите его и пользуйтесь всегда им.

Если вы работаете дома: не парьтесь, берите любой больше, чем 1024! (Меньшие номера зарезервированы для системных нужд).

Запускаем в puTTY python имя_программы.

Заходим на http://web-corpora.net:порт (или на http://localhost:порт, если вы запускаете flask на своём компьютере) и радуемся.

app.route

Первое: мы хотим, чтобы когда мы открываем страницу, нам _что-нибудь_ выдавалось.

Нам нужно сделать функцию, которая будет обрабатывать запросы и сказать, чтобы именно она вызывалась, когда пользователь хочет посмотреть адрес "/". (Flask опускает занудное повторение части "http://web-corpora.net:порт" и даёт нам указывать только то, что идёт в адресе после неё).

Flask пользуется для этого новой для нас конструкцией из питона (таких осталось совсем немного) – это декоратор. Декоратор – это пометка, которую мы приделываем к функции, чтобы функция приобрела какой-то новый смысл. Мы можем определять свои такие пометки, но об этом я сейчас рассказывать не буду. Если хотите, соответствующая тема в плане называется "как из питона сделать язык, заточенный под нашу задачу (domain-specific language, DSL): декораторы"

Использовать декораторы просто: нужно написать @ и текст декоратора перед функцией. Декораторов может быть сколько угодно (тогда их нужно стопочкой писать, по одному на строке).

   1 from flask import Flask
   2 
   3 app = Flask(__name__)
   4 
   5 @app.route("/")
   6 def index():
   7     return "Hello, world!"
   8 
   9 if __name__ == "__main__":
  10     app.run(host='0.0.0.0', port=2020)

@app.route("/"), будучи прилепленным к определению функции index, собственно, и говорит, что когда пользователь открывает путь / (то есть адрес http://web-corpora.net:порт/), нужно вызвать функцию index и показать пользователю то, что она вернула.

Теперь нам нужно перезапустить питон. Для этого сначала останавливаем его (Ctrl-C), а затем пускаем заново (можно вызвать предыдущую команду стрелочкой вверх).

И зайдём на http://web-corpora.net:порт/ – и там должно быть приветствие.

Мы можем к одной функции прилепить много декораторов. Тогда она будет отзываться на много разных адресов:

   1 from flask import Flask
   2 
   3 app = Flask(__name__)
   4 
   5 @app.route("/")
   6 @app.route("/hello")
   7 @app.route("/a/b")
   8 def index():
   9     return "Hello, world!"
  10 
  11 if __name__ == "__main__":
  12     app.run(host='0.0.0.0', port=2020)

Теперь приветствие висит и на http://web-corpora.net:порт/ , и на http://web-corpora.net:порт/hello , и на http://web-corpora.net:порт/a/b

Разумеется, мы можем описать сколько угодно таких функций и привесить их к сколько угодно разных адресов:

   1 from flask import Flask
   2 
   3 app = Flask(__name__)
   4 
   5 @app.route("/")
   6 @app.route("/hello")
   7 def index():
   8     return "Hello, world!"
   9 
  10 @app.route("/bye")
  11 def index():
  12     return "Goodbye, world!"
  13 
  14 if __name__ == "__main__":
  15     app.run(host='0.0.0.0', port=2020)

Аргументы

Гораздо интереснее, когда мы можем не перечислять разные адреса запроса, а взять кусочек запроса и положить в переменную. И мы это можем сделать. Для этого нужно кусочек запроса, который нам интересен, обозначить словом в угловых скобках (например <who>), а ещё сделать так, чтобы функция, которая этот запрос обрабатывает, принимала аргумент с таким именем:

   1 from flask import Flask
   2 
   3 app = Flask(__name__)
   4 
   5 @app.route("/")
   6 @app.route("/hello")
   7 def index():
   8     return "Hello, world!"
   9 
  10 @app.route("/bye/<who>")
  11 def index(who):
  12     return "Goodbye, {}!".format(who)
  13 
  14 if __name__ == "__main__":
  15     app.run(host='0.0.0.0', port=2020)

Шаблоны

Но играться со строками не интересно.

Создадим папочку templates (слово templates играет для Flask существенную роль: это то место, где он ищет файлы страничек) рядом с нашим питонским файлом и положим туда какую-нибудь html-ку, например, такую:

   1 <html>
   2         <head>
   3                 <title>Hello</title>
   4                 <style type="text/css">
   5                         h1 { color: red }
   6                 </style>
   7         </head>
   8         <body>
   9                 <h1>If you see this <s>DESTROY YOUR COMPUTER AT ONCE</s> it works!</h1>
  10         </body>
  11 </html>

Я положил её в файл templates/index.html (если смотреть относительно места, где лежит питонская программа).

Теперь нам надо в нашей программе проимпортировать ещё и функцию render_template, и в ответ на какой-нибудь запрос попросить её выдать нашу html-ку:

   1 from flask import Flask, render_template
   2 
   3 app = Flask(__name__)
   4 
   5 @app.route("/")
   6 @app.route("/hello")
   7 def index():
   8     return render_template("index.html")
   9 
  10 @app.route("/bye/<who>")
  11 def index(who):
  12     return "Goodbye, {}!".format(who)
  13 
  14 if __name__ == "__main__":
  15     app.run(host='0.0.0.0', port=2020)

Суперзадача: энциклопедия натуральных чисел!

Феноменальная новость!

Студент Иванов выучил весь натуральный ряд! Демонстрация феномена продолжается в аудитории 1234.

Мы хотим сделать сайт, в котором на каждой странице показывается число и есть ссылочки на соседние два числа.

Для этого мы хотим сделать сайт, у которого по запросу /число рисуется страница с числом и ссылками на страницы /число-1 и /число+1 (имеется в виду не дословно -1 и +1, а следующее и предыдущее число в натуральном ряду).

Начнём это делать с html-ки, то есть с её шаблона. Тут, вроде, всё просто, только нужно воткнуть куда-то число и ссылочки в шаблон. Число мы получим из переменной из питона. В шаблон мы можем подставлять питонские переменные в виде: {{переменная}} или {{выражение}} (там работает чуть-чуть видоизменённое подмножество питона)

   1 <html>
   2         <head>
   3                 <title>Hello</title>
   4                 <style type="text/css">
   5                         h1 { color: red }
   6                 </style>
   7         </head>
   8         <body>
   9                 <h1>{{number}}</h1>
  10                 <a href="/{{number-1}}">previous</a>
  11                 <a href="/{{number+1}}">next</a>
  12         </body>
  13 </html>

Осталось научиться передавать переменную в шаблон. Это очень просто: функция render_template принимает после названия шаблона сколько угодно каких-угодно именованных параметров, и они-то и становятся переменными для наших подстановок:

Нам нужно, чтобы по ссылке вида /<число> открывалась страница с number=число:

   1 from flask import Flask, render_template
   2 
   3 app = Flask(__name__)
   4 
   5 @app.route("/<number>")
   6 def index(number):
   7     return render_template("index.html", number=int(number))
   8 
   9 if __name__ == "__main__":
  10     app.run(host='0.0.0.0', port=2020)

Обзор типичной архитектуры сайта

Дабы понимать, к чему мы стремимся.

Как устроена типичная поисковая система?

Во-первых, у неё есть морда – это просто обычный html, который раздаётся без каких-либо изменений.

Во-вторых, в этом html есть формочка для поиска (это мы научимся делать в следующий раз), при заполнении которой отправляется запрос на сервер с тем, чтобы показать результаты. В этом запросе, среди прочего, есть текст, вбитый в формочку.

Теперь мы понимаем, что этот текст попадёт вот в такую питонскую функцию вроде нашей index. Эта функция, наверное, отправит запрос в базу данных и дождётся оттуда ответа, а потом результат подставит в шаблон, как мы и сделали с числом.

Конечно, чтобы сделать большой красивый сложный сайт, в него нужно вложить кучу сил. Да и с технической стороны у нас ещё осталась пара белых пятен (например, как делать формочки, и обрабатывать данные из них). Но, кажется, сейчас приципиальное устройство таких сайтов не кажется полной магией. Сейчас кажется, что это потребует ужасно много работы, но мы скоро узнаем, как шаблоны flask (а точнее, пакета jinja2, которым пользуется flask) могут нам сэкономить очень много повторной работы.

  1. Если вы вдруг решили освоить третий питон, то в python3.4 pip установлен из коробочки. (1)