Powershell и объектный pipe
Я задумался над тем, чтобы показать как могла бы выглядеть обработка логов на PowerShell. Как я уже говорил, pipe в PowerShell объектный, то есть по нему идёт не монолитный текст, а набор объектов. Вот я и попробую на примере показать что это.
Для начала настроим лог Apache так, чтобы его было удобнее парсить. К примеру, можно ввести символы табуляций — в логе они не встречаются и вполне подходят на роль разделителя:
LogFormat "%h\t%l\t%u\t%t\t\"%r\"\t%>s\t%b" common
CustomLog logs/access.log common
В логе у нас есть: хост клиента, его ident, имя пользователя (если была произведена HTTP-авторизация), дата и время запроса, метод-URL-версия-HTTP (одним полем), код ответа и длина отданного клиенту контента:
127.0.0.1 - - [03/Jan/2010:16:35:30 +0300] "GET /favicon.ico HTTP/1.1" 404 1976
127.0.0.1 - - [03/Jan/2010:16:35:32 +0300] "GET /a.html HTTP/1.1" 200 521
127.0.0.1 - - [03/Jan/2010:16:35:33 +0300] "GET /favicon.ico HTTP/1.1" 404 1976
Предположим, наша задача — разобрать лог, отобрать только те запросы, у которых код ответа 200, отсортировать по размеру контента и вывести в табличном виде название метода, URL и размер контента.
cat access.log | %`
{
$o = "" | Select-Object host, logname, user, date, url, code, len, method
$o.host, $o.logname, $o.user, $o.date, $o.url, $o.code, $o.len = $_.Split("`t")
[datetime]$o.date = $o.date -replace '^.([^:]+):(.+).$', '$1 $2'
"logname", "user", "len" | %{ If ($o.$_ -eq '-') { $o.$_ = $false } }
$o.method, $o.url = $o.url.SubString(1).Split()[0..1]
$o
} | ?{ $_.code -eq 200 } | Sort-Object -property len | Format-Table method, url, len
Итак, что здесь происходит. Читаем лог, проходимся по каждой его строке (%{ }), внутри цикла странным хаком с Select-Object создаём объект с заданными полями, разбиваем входную строку по символу табуляция, убираем у поля «date» первый и последний символы (там квадратные скобки) и двоеточие между датой и временем (такой формат понимает PowerShell), сразу преобразуем это значение в тип «datetime», у поле «logname», «user», «len» заменяем значение на False, если там «-» («пусто» в терминах лога Apache), поле «url» разделяем пробелу (там три значения — метод, URL и версия протокола), избавляемся от окаймляющих кавычек и записываем в соответствующие поля.
Последней строкой цикла выводим получившийся объект. До цикла по pipe шли объекты попроще — всего лишь наборы строк («System.String»), теперь идут более интересные объекты («System.Management.Automation.PSCustomObject» с заданными нами полями).
Из этих объектов мы вибираем только те, у которых поле «code» содержит значение 200 («?{}» — это короткий алиас «Where-Object»), сортируем по полю длины контента и выводим, форматируя в таблицу, три поля: метод запрос, URL и длину контента. На экране будет что-то подобное:
method url len
------ --- ---
GET / 4701
GET / 4701
GET / 4701
GET / 4701
GET /a.html 521
GET /a.html 521
Надо будет после праздников взглянуть на PowerShell 2.0, говорят, там очень много нового и интересного добавили.
Надеюсь небольшой holly war тут разрешён. А не кажется ли тебе, что PowerShell тяжелее bash и менее функционален и удобен интерактивных консолей Python или Ruby — то есть, ни рыба, ни мясо. Например, для Ruby (где само собой любое значение — набор объектов) даже есть специальная библиотека для замена консоли (с несколькими интересными идеями, например, отсутствием модальности текущей директории).
Тут получается так: на всех виндах у меня давно стоит Сygwin, bash/awk/perl/etc, и мне не нужен там никакой PowerShell. С другой стороны, если теперь в поставке есть PowerShell, то почему бы и нет?
Когда-то для ДОСа я активно использовал 4DOS, потом пересел на OS/2 и, пока не открыл REXX, юзал 4OS/2. Как только я проникся REXX и его полной объектной интеграцией в систему, 4OS/2 отпал как старая грязь с первым снегом.
Потом я пересел на Unix, и вообще забыл о проблеме качественного скриптинга. Но иногда хочется как раз интеграции с GUI винды, типа там видео проиграть, получить свойства объектов, кодеки там у видео, и всё такое. А в Cygwin c этим никак. И. насколько я понимаю, в винде с этим вообще никак было до появления PowerShell...
С другой стороны, нафиг мне эта винда, когда везде или Unix c его перлами/башами, либо MacOS с AppleScipt?..
Вообще, я тут подумал — если уж гонять апач на винде, то тогда можно и логи его попарсить павершеллом... Но такая извращённая жизнь обязательно выйдет боком — или болячкой, или семейными неурядицами :)
Надо делать то, что надо, а что не надо — делать не надо.
Комментарий для iskin.myopenid.com:
Что значит «тяжелее» bash? :) По мне так PS проще и более продуманный. И PS как shell для Windows уж точно функциональнее Python/Ruby — у него есть прямой и естественный доступ к COM/WMI/ADSI, то есть ко всем кишкам системы, а во второй версии аж транзакции.
Я не знаю Ruby, но около года попрограммировал на Python и пару месяцев на PS (плюс прочитал две книги), на мой взгляд, сделать из Python shell очень тяжело, надо делать обвязку. Ну попробуйте, для пример, скопировать там файлы по маске в другой каталог. Сделать это возможно, конечно, но так же просто как в каком-то shell?
Shell это ведь не только возможности как таковые, это определённая область, под которую язык надо затачивать.
Комментарий для jankkhvej.blogspot.com:
Сравнивать PS и bash некорректно, PS более молодая и продуманная вещь, сравнение будет не в пользу bash, конечно же. Как shell Perl тоже хуже, чем PS.
Ну как же никак? Можно было сходить из Windows Script Host из реестр и WMI и там всё выяснить, просто это не так удобно как сейчас.
На винде можно логи IIS запрашивать. Парсить их не надо, они уже придут в объектном виде, а логи Apache можно парсить и на других ОС: http://en.wikipedia.org/wiki/Pash_%28software%29
Именно это и ужасало.
Что до сравнений, очевидно же, если я на перле потрачу 2 минуты на написание нужного мне скрипта, то на изучение PS...
Кстати, неужели ещё где-то необходимо использовать IIS?
Комментарий для jankkhvej.blogspot.com:
Ну, PS изучается очень быстро. Не две минуты, конечно, но за две минуты на нём уже можно что-то писать.
А что с ним не так? Раньше это было дырявое ведро, но вот уже несколько последних лет — очень производительный веб-сервер.
Комментарий для Евгения Степанищева:
PS тяжелее bash так как тянет весь .Net framework. А bash есть на дистрибутивах «на дискетку».
Интерактивная консоль в IronRuby (Ruby внутри .Net) так же имеет доступ ко всем Windows API.
Я не знаю Python, но Ruby очень гибкий и вопрос удобства — просто в наборе удобных методов.
Собственно, стандартными библиотеками решение задачи с логами
File.readlines(’access.log’).map { |i| i.split(«\t») }.reject { |i| ’200’ != i[5] }.sort { |a, b| a[6] <=> b[6] }.each { |i| request = i[4].split(’ ’); puts «#{request[0]} #{request[1]} #{i[6]}» }
И всё решение в одну строчку с помощью удобных механизмов работы с массивами из функциональных ЯП (в Python Они тоже есть, но синтаксис больно некрасивый).
Комментарий для iskin.myopenid.com:
Ну, в общем, про Ruby ничего сказать не могу. Я его даже чуть-чуть не знаю.
dotNet framework, вроде как, не слишком много занимает. Не «на дискетку» (кому нужны сейчас дискетки?:), но по нынешним временам не кажется огромным. Да и в новых виндах он встроен, впрочем, как и PowerShell.
Мне не кажется некрасивым. Вполне себе сопоставимый синтаксис. Выглядеть будет примерно так же.
Комментарий для Евгения Степанищева:
Если на компьютере нет «новых виндов», то для этого, наверное, есть причины.
Возможно, те же самые, по которым «не слишком много» может оказываться многовато.
(Да и не все верят, что от перехода к новой его версии не сломается то, что раньше работало.)
А «на дискетку» — это newLISP, да.
Но его тоже придётся изучать.
Комментарий для Евгения Степанищева:
«На дискетку» — имеется в виду роутеры и другие мелкие железки. То есть PS нельзя заложить в основу ОС, как sh в UNIX. Те же низкоуровневые скрипты включения ОС или куча мелких системных скриптов — тут точно не место виртуальной машине.
Комментарий для iskin.myopenid.com:
Пройдёт 2-3 года и в роутерах станет больше памяти, не проблема, правда же?
Как это «в основу OС»?
Комментарий для baka.name:
Ну, старые машины, бог с ними. Когда-нибудь они вымрут, это не причина задерживать прогресс. Один из компьютеров у меня — довольно старый Pentium-III, на нём стоит Windows XP, много лет без переустановки.
На этой XP, соответственно, уже может работать PS (Windows 7 там не заработает — памяти всего 512МБ).
Комментарий для Евгения Степанищева:
bash является интерфейсом по умолчанию, следовательно должен работать на любых устройствах — вырастет память у роутеров (не будем думать зачем там .Net ;) ), так Linux будут ставить на мелкие датчики, которые будут разбрасывать по лесу для контроля погоды («умная пыль») и там тоже понадобится bash для сервисных нужд.
В основе ОС — это значит, что bash используется в скриптах запуска ОС (/etc/init.d/) в куче мелких системных утилит, которые часто запускаются. Грузить для этого всю CLR-VM со стеком библиотек .Net — неправильно.
Комментарий для iskin.myopenid.com:
А как эта библиотека называется?
Комментарий для elv1s.ru:
Вспомнил Ruby-библиотеку для консоли — rush, http://rush.heroku.com/
Комментарий для iskin.myopenid.com:
Когда-то, много лет назад, когда я активно писал на ассемблере, а пучок игр помещался на дискету, вышла игра «Prince II». Как сейчас помню — она занимала пять мегабайт. Тогда для меня это было невероятным расходом. Я недоумевал и переживал (куда катится мир), что какая-то игрушка занимает целых пять мегабайт.
Мораль такова — что сейчас кажется нехеровым расходом, завтра окажется обыденностью.
Я смотрю куча мелких системных утилит, чем дальше, тем больше, переползает на Python. Да и в init.d никто не мешает использовать другой язык.
Всё-таки в «основу ОС» в Unix встроена концепция «всё — файл», а вот там, где PowerShell — его концепции «всё — объект» в ОС нету. В этом собственно и есть фейл PowerShell — он надстройка, а не оболочка к функциям ОС. И это реально бесит, если вспоминать то, что концепция «всё — объект» была ещё в 1997-ом в OS/2.
Комментарий для jankkhvej.blogspot.com:
А что вам даёт основание это утверждать?
del a.txt — удаление файла a.txt
del variable:a — удаление переменной «a»
del hkcu:AppEvents — удаление ветки реестра HKCU/AppEvent
Это к концепции «всё файл» (хотя это объекты, конечно). Добраться до WMI не настолько тривиально, но тоже довольно просто.
Можно ли из произвольной программы с использованием стандартной функции из стандартной библиотеки найти и открыть объект N, который, к примеру документ ворда на рабочем столе и получить его автора? В OS/2 можно.
Можно ли прочитать данные из произвольного устройства, типа флешки или сети, простой функцией из стандартной библиотеки? В Unix можно.
А вот в Windows надо вызывать PowerShell. Вот и вся разница.
Комментарий для jankkhvej.blogspot.com:
А… мы на недостатки Windows и отдельные достоинства других ОС перешли? Не, я не хочу об этом спорить :) Я про PowerShell и исключительно про него.
это был ответ на вопрос «А что вам даёт основание это утверждать?». Концепции PowerShell на Windows не распостраняются же.
Комментарий для jankkhvej.blogspot.com:
В DOS, как не странно, эта концепция присутствовала. Например, принтер там был prn, COM1 — com1, а с HIMEM можно было общаться через файл XMSXXXX0.
в DOS? Принтер да, а, к примеру, сканер?
То-то же.
Комментарий для jankkhvej.blogspot.com:
А во времена DOS были сканеры?