пятница, 29 января 2010 г.

Просто о xargs

Долгими зимними вечерами я сидел и думал "вот придёт светлое время, я сяду и как следует разберусь с этой загадочной утилиткой xarg". Ну вот время похоже и пришло - я сел разбираться. Первое, что мне бросилось в глаза, это то, что man к ней довольно загадочный, и с первого раза не просветляет. Статья на википедии понимания тоже не добавила, а скорее даже запутала, поэтому я решил провести своё собственное расследование, и написать по этому поводу небольшой мануальчик. Как известно, пока объясняешь и сам поймёшь :)

Итак, xargs.

xargs это такая утилита командной строки, позволяющая вызвать любую команду с аргументами, взятыми из стандартного входа. Причём аргументы можно передать все сразу, а можно группировать по несколько штук. Изучать мы будем xargs версии 4.4.0, при чём по рекомендации man-а будем использовать только новые аргументы, не помеченные как deprecated(лучше сразу привыкать работать правильно).

Итак первое, что стоит понять, это то, как xargs обрабатывает входящий поток и делит его на аргументы. Есть несколько режимов, зависящих от опций:

1. Обычный. По умолчанию разделителем аргументов считается любой пробельный символ: пробел, табуляция, вертикальная табуляция или перевод строки. Но как и в командной оболочке можно использовать "" или \ что бы предотвратить разбиение аргумента.

2. Обычный, с группировкой. Режим, включающийся параметром -L. Практически идентичен предыдущему, за исключением того, что xargs запоминает, какой аргумент на какой строке находится. Более того, если строка оканчивается пробелом или табуляцией, следующая строка считается продолжением текущей.

3. По строкам. Включается при использовании опции -I или -0. При этом вся строка считается одним целым аргументом, несмотря на пробелы и табуляции внутри. Для -I концом строки является символ '\n' а для -0 символ '\0'

Проведём пару испытаний, что бы лучше понять всё это. Создадим файл test с следующим содержимым(== в файл заносить не надо):
==
arg1
arg2 space
"arg3 quoted"
arg4\ escaped
arg5 with
continue
==
(После 'arg5 with' должен быть пробел)
А так-же напишем небольшой скрипт tp, который будет выводить свои аргументы разделяя их символом ':' и количество:
==
#!/bin/bash
echo -n "@$#"
while [[ $1 != "" ]]; do echo -n ":$1"; shift; done
echo
==

Обычный режим(выделение аргументов по пробельным символам):
x $ cat test | xargs ./tp
@8:arg1:arg2:space:arg3 quoted:arg4 escaped:arg5:with:continue
Файл был разбит на аргументы по пробельным символам, но строки взятые в кавычки и экранированные символом '\' остались целыми.

Обычный режим с группировкой по строкам не отличается от предыдущего на этом этапе.

Разбиение по строкам. Создадим второй тестовый файл следующей командой:
x $ cp test testz && printf "\0arg6" >> testz
Проверим
x $ cat testz | xargs -0 ./tp
@2:arg1
arg2 space
"arg3 quoted"
arg4\ escaped
arg5 with
continue
:arg6

Как можно видеть аргумента всего 2. Первый длинный, сохранивший переводы строк, кавычки и \, а второй arg6. В файле они разделены нулевым символом.

По поводу разделения параметров можно ещё сказать о опции -d, которая указывает новый разделитель. Например попробуем использовать '3' как разделитель.
x $ cat test | xargs -d 3 ./tp
@2:arg1
arg2 space
"arg: quoted"
arg4\ escaped
arg5 with
continue
Произошло разделение файла на 2 части на месте символа '3'. Что примечательно, таким образом можно эмулировать опцию -0
x $ cat testz | xargs -d "\x00" ./tp
@2:arg1
arg2 space
"arg3 quoted"
arg4\ escaped
arg5 with
continue
:arg6

С деление входного потока на аргументы кажется разобрались, переходим к подстановке параметров.

Итак, xarg после своих опций ждёт команду, которую и будет выполнять. Все входящие аргументы разбиваются на группы, после чего заданная команда вызывается для каждой группы, и в неё передаются все аргументы из этой группы.

Теперь рассмотрим, как формируются группы.

1. Если опций нет, то группа одна, в неё попадают все аргументы из потока ввода. Группа бесконечного размера, так сказать :)

2. Опция -L n задаёт группировку по строкам. В команду передаются аргументы находящиеся на n строках. Продемонстрирую на примерах.
Группировка по 1 строке:
x $ cat test | xargs -L 1 ./tp
@1:arg1
@2:arg2:space
@1:arg3 quoted
@1:arg4 escaped
@3:arg5:with:continue
Видно, что вторая строка содержит 2 аргумента, потому как они оба на одной строке. А а последняя вообще 3, так как предпоследняя строка "удлинняется" за счёт пробела в конце.

Теперь группировка по 2 строки. В команду попадают строки 1 и 2; 3 и 4; и сиротка 5-ая:
x $ cat test | xargs -L 2 ./tp
@3:arg1:arg2:space
@2:arg3 quoted:arg4 escaped
@3:arg5:with:continue

3. Группировка по аргументам, задаваемая опцией -n x. Тут всё прозрачно: аргументы группируются по x штук и передаются в команду.
По одному аргументу:
x $ cat test | xargs -n 1 ./tp
@1:arg1
@1:arg2
@1:space
@1:arg3 quoted
@1:arg4 escaped
@1:arg5
@1:with
@1:continue
По 2 аргумента:
x $ cat test | xargs -n 2 ./tp
@2:arg1:arg2
@2:space:arg3 quoted
@2:arg4 escaped:arg5
@2:with:continue

3. Режим с подстановкой - опция -I. Для начала надо напомнить, что в данном режиме аргументы из потока ввода разбираются по особому. Каждая строка это один целый аргумент, склеивание строк не производится. Во вторых, у опции -I имеется параметр - строка, которая заменяется в команде на аргумент:
x $ echo -e "A B\nC D" | xargs -I _ ./tp =_+_=
@1:=A B+A B=
@1:=C D+C D=
Легко заметить, что символ _ задан как строка подстановки аргумента, которая используется в команде 2 раза. Так же видно, что аргументы выделяются целыми строками, и пробел не влияет на разбор. Команда вызывается для каждого аргумента.

С подстановкой всё. Рассмотрим оставшиеся важные опции
-r - не выполнять команду, если нет аргументов:
x $ cat /dev/null | xargs ./tp
@0
x $ cat /dev/null | xargs -r ./tp
x $
Как видим, во втором случае команда не выполнилась.

-p - xargs будет запрашивать подтверждение на выполнение каждой команды.

На этом небольшой мануал завершён. Он оказался не совсем кратеньким, зато надеюсь понятненьким ;)

четверг, 28 января 2010 г.

Шпоры

Распечатал только что шпоры для подружки жены. Учатся они в одном универе, на какой-то ужасной специальности. Только представьте, 51 страница 10-ым шрифтом, с полусантиметровыми полями. И это шпаргалки. По одному предмету.

o_O

среда, 27 января 2010 г.

Дело было вечером, делать было нечего.

Жена отобрала ноутбук и сидела за ним весь вечер. Хочет вспомнить молодость и связать мне шарфик, вот изучает-с. Поскольку мотать шерсть не надо, я был отправлен на свободный промысел, искать себе занятие, то есть.

И решил сделать давно задуманные шары для жонглирования(ну или у кого что фантазия подскажет). Идею бессовестно позаимствовал на каком-то иностранном блоге и адаптировал к своим условиям.

Итак имеем:
- 12 воздушных шариков.
- Килограмм нелюбимых круп(я выбрал горох).
- Какая-нибудь трубка (например картонный "вал" от пищевого целлофана).
- Стакан или любая другая ёмкость. Для пущей точности их нужно 4.
- Ножницы_которые_режут.


Шарики кстати перед использованием стоит надуть, что бы они стали более эластичные. Те которые я купил так вообще страдали крайней степенью жёсткости. Когда надуваешь его первый раз, аж уши закладывает - выложится надо неплохо. Ради лулзов предложил один шарик надуть жене - она так и не смогла :)
Значит продули шарики, теперь по одному натягиваем их на трубку, как... ну как китайский презерватив на негра:


Затем засыпаем в трубку горох(ну или что вы там выбрали):

Разумеется, так он вам в шарик и посыпался. Надо его подтолкнуть - придерживая край шарика на трубке дуем в трубку, шарик надувается и горох элегантно ссыпается в шарик. Повторяем, пока не достигнем желаемого размера шара.

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


И потом засыпал горох обратно в шары по вышеописанной методике. Получаются вот такие яблоки с ручкой:


Теперь заворачиваем горло шарика внутрь. Можно и просто отрезать шею, но тогда сложнее будет сделать следующий шаг.


Затем подходим к самому сложному. Берём пустой шарик, отрезаем ему горло и пытаемся натянуть на яблоко. Поскольку это сделать невозможно(на первый взгляд), то мы призываем на помощь... нет, не жену. Жене вполне может придти в голову очевидная бесполезность ваших манипуляций, а например мытьё посуды явным "стоящим делом". Нет, мыть посуду сегодня мы не будем. Призываем на помощь терпение и немного смекалки.

Создаём из яблока яйцо:

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

Получаются такие вот шары:

Белый это вывернутый наизнанку шарик, а рыжий я сделал раньше.

Вот так практически из ничего делается пару бесполезных шаров.

вторник, 26 января 2010 г.

А ведь Холмс был прав....

Когда говорил, что большинство людей не обращают внимания на окружающие их мелочи.
Я уже около 2 лет езжу на работу на автобусе №51, почти каждый день туда-обратно. Казалось бы, для меня этот маршрут должен был стать чуть ли не родным, но...

Некоторое время назад я решил вписать на карте openstreetmap.org этот самый "родной" маршрут. Приступил к нанесению остановок и задумался, а какие там остановки-то? Пару штук помню и всё. Полез в CityInfo и выпал в осадок. Оказывается на маршруте есть остановки, о которых я и не подозревал. Спроси меня "есть остановка X на маршруте?", я бы сказал - нема! 'Х' я написал потому, что... ну сами понимаете, не могу вспомнить как же она называется :)

Мда. И почти каждый день я слышу "следующая остановка Х". Ё-маё, ну как же она называется-то! :)

воскресенье, 24 января 2010 г.

Настроил iptables, теперь никто не ворует

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

# INPUT
iptables -P INPUT ACCEPT

# OUTPUT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A OUTPUT -o ppp0 -m owner --uid-owner dnl-guest -j ACCEPT
iptables -A OUTPUT -o ppp0 -m owner --uid-owner portage -j ACCEPT
iptables -A OUTPUT -m owner --uid-owner root -j ACCEPT
iptables -A OUTPUT -m owner --uid-owner sazarkevich -j ACCEPT

iptables -A OUTPUT -j REJECT

На вход пока что все разрешены, позже надо бы добавить что-то вроде

iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

а всё остальное запретить.

На выход разрешено всем на lo.
На ppp0 разрешены для пользователей portage и dnl-guest: portage качает обновления, с платника этого делать не стоит. Под пользователем dnl-guest запускаю торрент: su dnl-guest -c "rtorrent ..."
root и sazarkevich могут лазить везде и всюду.
Остальные получают недвусмысленный отказ(REJECT).

Была сначала мысль сделать через параметр --gid-owner: создать группы inet и inet-guest. Кто в первой группе - полный доступ, кто во второй группе - только гостевой.
Но как оказалось, эта группа должна быть основной. В man-е этого почему-то не сказано и я долго пытался понять, почему для одних правил --gid-owner работает, а для других - нет. Жаль, было бы красиво.

пятница, 22 января 2010 г.

Странное

Мои родители довольно далёкие от компьютеров человеки, поэтому зачастую видя меня корпящим над линуксовой консолью, они обвиняюще заявляют "А ты всё в компьютер играешься ?!"

Играюсь ли я в компьютер? Нет, блин, я в него работаю!

;)

понедельник, 18 января 2010 г.

Подсветка строк

Задумался я недавно. Вот grep есть, красиво подсвечивает строки, но всё остальное, что не попало под шаблон, не показывает. А мне захотелось, что бы показывало всё, а кое какие строки даже и подсвечивались.
Сказано - сделано. Полез в гугль, покопался и нашёл что-то похожее на правду: утилиту hlstring. Единственный недостаток - в ебилдах я её не нашёл, поэтому пришлось наморщить ум.

Результатом морщения оного стал вот такой скриптик:


#!/bin/bash

IN_COLOR="^[[0;31;40m"
OUT_COLOR="^[[0;37;40m"

[[ $1 == "" ]] && echo "Usage: $0 [-c color] [--raw-cond] " && exit

while [[ $2 != "" ]]; do
[[ $1 == "--" ]] && shift && break

if [[ $1 == "-c" ]]; then
IN_COLOR="^[[0;$2;40m"
shift
continue
fi

if [[ $1 == "--raw-cond" ]]; then
RAW_COND=true
fi

shift
done

if [[ $RAW_COND == "" ]];then
SED_COND="/$1/"
else
SED_COND="$1"
fi

sed -re "${SED_COND} s/(.*)/$IN_COLOR\1$OUT_COLOR/"

Ну, что тут и как понять вроде не сложно. Ищем sed-ом строки и обрамляем ESC кодами. Коды забиты в шаблон поэтому не факт, что оно будет правильно работать на всех терминалах. Но на xterm - вполне.

Закатал его в файлик highlight.sh, и добавил alias в zsh - hl.

Пример использования:
leela ~ # iptables -L -v | hl eth0 | hl -c 33 --raw-cond 1,2
Выводим правила iptables
Подсвечиваем строки, содержащие eth0 (по умолчанию красным)
И подсвечиваем первую и вторую строку цветом 33 (им оказался жёлтый).
-c как вы поняли цвет, --raw-cond задаёт условие выбора строк в sed как есть (по умолчанию обрамляется /)

Вот даже и картинку сделал:


P/S/ Кстати, можно видеть, что через eth0 я скачал 19 метров (это примерно за сутки) платного трафика, а через бесплатный гостевой доступ уже 3.8 Гига. Похоже больше трафик не крадут ;) А ещё похоже, что первые 4 правила вообще не нужны.

З.Ы.Ы. Если кто захочет скопировать скрипт, то он у вас не заработает. Чтоб сработал надо везде в тексте заменить ^[ на реальный символ ESC. В консоли(и в vim-е тоже) он вводится путём нажатия Ctr+V и затем ESC.

пятница, 15 января 2010 г.

Настройка сети в VMWare

Купил недавно USB веник на 500 гиг. Тут же встала проблема разбивки его на разделы. Впрочем, сама разбивка не представляет сложности: 100 гиг под FAT32(что бы DVD плеер мог читать) и 400 гиг под ext4. Дома то у меня линукс, вот и захотелось родную файловую систему на венике.

А вот теперь проблема - как из винды добраться до этого раздела? Традиционно в винде поддержка файловых систем довольно куцая, а надо. Фильмы там слить у соседа, на работу что-то принести.

Ну, вообще-то это тоже не проблема - сделал виртуалку в VMWare, поставил туда Debian (на 500 метров влез впритык, не могу теперь туда поставить даже vim :). Настроил, как мне показалось, сеть, скачал из инета и установил samba, чтоб шарить раздел ext4. Всё настроил, запустил.

Ну и вот собственно проблема. Винда в упор не может достучаться до расшаренных папок. Пинговать - пожалста, из Debian-а виндовые шары доступны, инет доступен, назад - нет. Пару дней бился головой об стол, перенастраивал самбу, ничего не помогало.

Вот. А настройки сети у меня были такие:
хост (с виндой) 192.168.1.10
гость (дебиан) 192.168.1.200, интерфейс bridged
Всё вроде пучком, подсеть одна, адреса не повторяются.
И в конце концов я заметил пару сетевых интерфейсов VMnet1 и VMnet2, адреса которых были несколько необычными: 192.168.47.1, 192.168.176.1
Потратив ещё пару часов, я наконец добился того, чего добился Коля Остен-Бакен от подруги детства, польской красавицы Инги Зайонц, я добился любви. Любви между виндой и самбой.

Короче, я оставил первый сетевой интерфейс в виртуалке для доступа к инету, и добавил ещё один - host only. Настроил VMnet1 на IP 192.168.2.1 а в дебиане соответствующий eth1 на 192.168.2.2. И всё чудесным образом заработало. Винда не только заходит на шары, но ещё и вполне нормально видит сам виртуальный комп с дебианом, чего я уж никак не ожидал.

Осталось только выяснить, почему невозможно работать через bridged интерфейс.

вторник, 5 января 2010 г.

А.... украли трафик!

Ну точнее, я его сам и про...ал.

пару месяцев у меня был анлим, и я качал сериалы со страшной, всеразрушающей силой. Причём и по платному и по гостевому соединению(почему всеразрушающей? да просто пришлось rtorrent надломать, чтоб он сообщал хорошие цифры отдачи, вот вам и разрушения).

Гостевое соединение я аккуратно отделил от платного: платное идёт через модем -> eth0
а гостевое через поднимающийся на компе ppp0. Соответственно соорудил пару правил для iptables, что бы входящие с eth0 на порты 60000-60011 (порты rtorrent) обрубались на корню. На исходящие я ничего не навешивал, поскольку исходящий порт может быть любым, а как привязать правило к имени процесса я не стал копать. Я решил, что раз входить пакеты не смогут, значит и исходящие потихоньку сами собой заглохнут. Теперь один rtorrent усиленно качал через eth0, второй через ppp0, и друг к другу в гости они не ходили.

И вот, я решил, что можно бы временно переключится на другой, потрафиковый, режим. Взял и переключился. Платный торрент отсановил, а гостевой нет - пущай покачает.

И вот, за 2 дня я вижу в статистике 1 гиг. Причём и входящих и исходящих. Украли!!? Нет, сам прое.. ээ... ну, это самое.

Похоже я не до конца разобрался с iptables. Бегает платный трафик в обход моих правил... Есть предположение, что установленные мной правила не распространяются на уже установленные соединения - исходящие то не режутся. Надо думать. Только нечем :(

Что-то как-то всё никак

Не устаю удивляться творениям рук майкрософтовских. Я ещё могу понять, что cmd.exe жуткое убожество, предназначенное для разовых действий и на нормальную, рабочую консоль никак не тянет. Ну там домохозяйки, всё такое.

А я пишу консольные лабы, и тестировать их удобно именно из консоли. Набил в текстовый файл матрицу 5 на 5, потом просто выполняешь
Lab7 < test
и видишь результат вычислений. Что-то неправильно - перекомпилял и снова проверил.
Приятно, что не надо каждый раз корячится и набивать эту долбанную матрицу.

Но есть и бочка дёгтя в этой ложечке мёда. Переходить в другую директорию довольно занудно без нормального автокомплита, поэтому я просто закрываю консоль и открываю из тотала новую. Знаете, что надо сделать, чтоб закрыть консоль в Линуксе? Нажать Ctrl+D. В cmd.exe надо каждый раз корячится и набирать exit.

Ну вот. А недавно услышал про чудо инженерной мысли - PowerShell. Скачал, установил. Проверил автокомплит - такой-же угрёбищный. Ладно, попробовал
Lab7 < test
и оппа.
PS C:\Lab7\Debug> .\Lab7.exe < 1
The redirection operator '<' is not supported yet.
At line:1 char:13
+ .\Lab7.exe < <<<< 1
А вот такая команда работает:
PS C:\Lab7\Debug> cat 1 | .\Lab7.exe

Не, ну это вообще какой-то идиотизм. Зачем мне новая консоль, в которой надо набирать больше? Да и выходить по Ctrl+D они так и не научились....

Пойду я лучше в Far...

З.Ы. Только что вспомнил, что в фаре вообще нет автокомплита :( Ну что за...