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, говорят, там очень много нового и интересного добавили.
3 января 2010 16:08

A.I. (iskin.myopenid.com)
4 января 2010, 03:38

Надеюсь небольшой holly war тут разрешён. А не кажется ли тебе, что PowerShell тяжелее bash и менее функционален и удобен интерактивных консолей Python или Ruby - то есть, ни рыба, ни мясо. Например, для Ruby (где само собой любое значение - набор объектов) даже есть специальная библиотека для замена консоли (с несколькими интересными идеями, например, отсутствием модальности текущей директории).

jankkhvej (jankkhvej.blogspot.com)
4 января 2010, 10:59

Тут получается так: на всех виндах у меня давно стоит С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?..

jankkhvej (jankkhvej.blogspot.com)
4 января 2010, 11:02

Вообще, я тут подумал - если уж гонять апач на винде, то тогда можно и логи его попарсить павершеллом... Но такая извращённая жизнь обязательно выйдет боком - или болячкой, или семейными неурядицами :)
Надо делать то, что надо, а что не надо - делать не надо.

bolk (bolknote.ru)
4 января 2010, 11:44, ответ предназначен A.I. (iskin.myopenid.com):

Что значит «тяжелее» bash? :) По мне так PS проще и более продуманный. И PS как shell для Windows уж точно функциональнее Python/Ruby — у него есть прямой и естественный доступ к COM/WMI/ADSI, то есть ко всем кишкам системы, а во второй версии аж транзакции.

Я не знаю Ruby, но около года попрограммировал на Python и пару месяцев на PS (плюс прочитал две книги), на мой взгляд, сделать из Python shell очень тяжело, надо делать обвязку. Ну попробуйте, для пример, скопировать там файлы по маске в другой каталог. Сделать это возможно, конечно, но так же просто как в каком-то shell?

Shell это ведь не только возможности как таковые, это определённая область, под которую язык надо затачивать.

bolk (bolknote.ru)
4 января 2010, 11:55, ответ предназначен jankkhvej (jankkhvej.blogspot.com):

Тут получается так: на всех виндах у меня давно стоит Сygwin, bash/awk/perl/etc, и мне не нужен там никакой PowerShell.
Сравнивать PS и bash некорректно, PS более молодая и продуманная вещь, сравнение будет не в пользу bash, конечно же. Как shell Perl тоже хуже, чем PS.
типа там видео проиграть, получить свойства объектов, кодеки там у видео, и всё такое. А в Cygwin c этим никак. И. насколько я понимаю, в винде с этим вообще никак было до появления PowerShell…
Ну как же никак? Можно было сходить из Windows Script Host из реестр и WMI и там всё выяснить, просто это не так удобно как сейчас.
если уж гонять апач на винде, то тогда можно и логи его попарсить павершеллом... Но такая извращённая жизнь обязательно выйдет боком - или болячкой, или семейными неурядицами :)
На винде можно логи IIS запрашивать. Парсить их не надо, они уже придут в объектном виде, а логи Apache можно парсить и на других ОС: http://en.wikipedia.org/wiki/Pash_(software)

jankkhvej (jankkhvej.blogspot.com)
4 января 2010, 12:03

Ну как же никак? Можно было сходить из Windows Script Host из реестр и WMI и там всё выяснить, просто это не так удобно как сейчас.
Именно это и ужасало.

Что до сравнений, очевидно же, если я на перле потрачу 2 минуты на написание нужного мне скрипта, то на изучение PS...

Кстати, неужели ещё где-то необходимо использовать IIS?

bolk (bolknote.ru)
4 января 2010, 13:00, ответ предназначен jankkhvej (jankkhvej.blogspot.com):

Ну, PS изучается очень быстро. Не две минуты, конечно, но за две минуты на нём уже можно что-то писать.
Кстати, неужели ещё где-то необходимо использовать IIS?
А что с ним не так? Раньше это было дырявое ведро, но вот уже несколько последних лет — очень производительный веб-сервер.

A.I. (iskin.myopenid.com)
4 января 2010, 16:28, ответ предназначен bolk (bolknote.ru):

PS тяжелее bash так как тянет весь .Net framework. А bash есть на дистрибутивах «на дискетку».
Интерактивная консоль в IronRuby (Ruby внутри .Net) так же имеет доступ ко всем Windows API.
Я не знаю Python, но Ruby очень гибкий и вопрос удобства — просто в наборе удобных методов.

A.I. (iskin.myopenid.com)
4 января 2010, 16:35

Собственно, стандартными библиотеками решение задачи с логами
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 Они тоже есть, но синтаксис больно некрасивый).

bolk (bolknote.ru)
4 января 2010, 16:54, ответ предназначен A.I. (iskin.myopenid.com):

Ruby очень гибкий и вопрос удобства — просто в наборе удобных методов
Ну, в общем, про Ruby ничего сказать не могу. Я его даже чуть-чуть не знаю.
PS тяжелее bash так как тянет весь .Net framework. А bash есть на дистрибутивах «на дискетку».
dotNet framework, вроде как, не слишком много занимает. Не "на дискетку" (кому нужны сейчас дискетки?:), но по нынешним временам не кажется огромным. Да и в новых виндах он встроен, впрочем, как и PowerShell.
в Python Они тоже есть, но синтаксис больно некрасивый
Мне не кажется некрасивым. Вполне себе сопоставимый синтаксис. Выглядеть будет примерно так же.

baka.name (baka.name)
4 января 2010, 17:36, ответ предназначен bolk (bolknote.ru):

dotNet framework, вроде как, не слишком много занимает
Да и в новых виндах он встроен, впрочем, как и PowerShell.
Если на компьютере нет "новых виндов", то для этого, наверное, есть причины.
Возможно, те же самые, по которым "не слишком много" может оказываться многовато.
(Да и не все верят, что от перехода к новой его версии не сломается то, что раньше работало.)

А "на дискетку" - это newLISP, да.
Но его тоже придётся изучать.

A.I. (iskin.myopenid.com)
4 января 2010, 18:26, ответ предназначен bolk (bolknote.ru):

"На дискетку" - имеется в виду роутеры и другие мелкие железки. То есть PS нельзя заложить в основу ОС, как sh в UNIX. Те же низкоуровневые скрипты включения ОС или куча мелких системных скриптов - тут точно не место виртуальной машине.

bolk (bolknote.ru)
4 января 2010, 22:00, ответ предназначен A.I. (iskin.myopenid.com):

"На дискетку" - имеется в виду роутеры и другие мелкие железки.
Пройдёт 2-3 года и в роутерах станет больше памяти, не проблема, правда же?
То есть PS нельзя заложить в основу ОС, как sh в UNIX
Как это «в основу OС»?

bolk (bolknote.ru)
4 января 2010, 22:08, ответ предназначен baka.name:

Если на компьютере нет «новых виндов», то для этого, наверное, есть причины.
Ну, старые машины, бог с ними. Когда-нибудь они вымрут, это не причина задерживать прогресс. Один из компьютеров у меня — довольно старый Pentium-III, на нём стоит Windows XP, много лет без переустановки.

На этой XP, соответственно, уже может работать PS (Windows 7 там не заработает — памяти всего 512МБ).

A.I. (iskin.myopenid.com)
4 января 2010, 22:29, ответ предназначен bolk (bolknote.ru):

bash является интерфейсом по умолчанию, следовательно должен работать на любых устройствах — вырастет память у роутеров (не будем думать зачем там .Net ;) ), так Linux будут ставить на мелкие датчики, которые будут разбрасывать по лесу для контроля погоды («умная пыль») и там тоже понадобится bash для сервисных нужд.

В основе ОС — это значит, что bash используется в скриптах запуска ОС (/etc/init.d/) в куче мелких системных утилит, которые часто запускаются. Грузить для этого всю CLR-VM со стеком библиотек .Net — неправильно.

ELV1S (elv1s.ru)
4 января 2010, 22:37, ответ предназначен A.I. (iskin.myopenid.com):

... Например, для Ruby (где само собой любое значение - набор объектов) даже есть специальная библиотека для замена консоли (с несколькими интересными идеями, например, отсутствием модальности текущей директории).
А как эта библиотека называется?

A.I. (iskin.myopenid.com)
4 января 2010, 22:45, ответ предназначен ELV1S (elv1s.ru):

Вспомнил Ruby-библиотеку для консоли — rush, http://rush.heroku.com/

bolk (bolknote.ru)
5 января 2010, 10:21, ответ предназначен A.I. (iskin.myopenid.com):

Грузить для этого всю CLR-VM со стеком библиотек .Net — неправильно.
Когда-то, много лет назад, когда я активно писал на ассемблере, а пучок игр помещался на дискету, вышла игра «Prince II». Как сейчас помню — она занимала пять мегабайт. Тогда для меня это было невероятным расходом. Я недоумевал и переживал (куда катится мир), что какая-то игрушка занимает целых пять мегабайт.

Мораль такова — что сейчас кажется нехеровым расходом, завтра окажется обыденностью.
В основе ОС — это значит, что bash используется в скриптах запуска ОС (/etc/init.d/) в куче мелких системных утилит, которые часто запускаются.
Я смотрю куча мелких системных утилит, чем дальше, тем больше, переползает на Python. Да и в init.d никто не мешает использовать другой язык.

jankkhvej (jankkhvej.blogspot.com)
5 января 2010, 12:40

Всё-таки в "основу ОС" в Unix встроена концепция "всё - файл", а вот там, где PowerShell - его концепции "всё - объект" в ОС нету. В этом собственно и есть фейл PowerShell - он надстройка, а не оболочка к функциям ОС. И это реально бесит, если вспоминать то, что концепция "всё - объект" была ещё в 1997-ом в OS/2.

bolk (bolknote.ru)
5 января 2010, 16:51, ответ предназначен jankkhvej (jankkhvej.blogspot.com):

а вот там, где PowerShell - его концепции "всё - объект" в ОС нету
А что вам даёт основание это утверждать?

del a.txt — удаление файла a.txt
del variable:a — удаление переменной «a»
del hkcu:AppEvents — удаление ветки реестра HKCU/AppEvent

Это к концепции «всё файл» (хотя это объекты, конечно). Добраться до WMI не настолько тривиально, но тоже довольно просто.

jankkhvej (jankkhvej.blogspot.com)
5 января 2010, 17:58

Можно ли из произвольной программы с использованием стандартной функции из стандартной библиотеки найти и открыть объект N, который, к примеру документ ворда на рабочем столе и получить его автора? В OS/2 можно.
Можно ли прочитать данные из произвольного устройства, типа флешки или сети, простой функцией из стандартной библиотеки? В Unix можно.
А вот в Windows надо вызывать PowerShell. Вот и вся разница.

bolk (bolknote.ru)
6 января 2010, 09:16, ответ предназначен jankkhvej (jankkhvej.blogspot.com):

А… мы на недостатки Windows и отдельные достоинства других ОС перешли? Не, я не хочу об этом спорить :) Я про PowerShell и исключительно про него.

jankkhvej (jankkhvej.blogspot.com)
6 января 2010, 15:44

это был ответ на вопрос "А что вам даёт основание это утверждать?". Концепции PowerShell на Windows не распостраняются же.

bolk (bolknote.ru)
8 января 2010, 16:44, ответ предназначен jankkhvej (jankkhvej.blogspot.com):

В DOS, как не странно, эта концепция присутствовала. Например, принтер там был prn, COM1 — com1, а с HIMEM можно было общаться через файл XMSXXXX0.

jankkhvej (jankkhvej.blogspot.com)
8 января 2010, 17:30

в DOS? Принтер да, а, к примеру, сканер?
То-то же.

bolk (bolknote.ru)
8 января 2010, 22:43, ответ предназначен jankkhvej (jankkhvej.blogspot.com):

А во времена DOS были сканеры?

Ваше имя или адрес блога (можно OpenID):

Текст вашего комментария, не HTML:

Кому бы вы хотели ответить (или кликните на его аватару)