esyr: (Default)
Вероятно, многие знают, что при помощи shell built-in read можно построчно читать всякое; особенно это актуально при считывании списка файлов, которые потенциально могут содержать пробелы (например, в выдаче ls или find) или чего-то подобного. Обычно это делается так:

Построчное чтение из файла:
while read line
do
  # code
done < file

Построчное чтение результата выполнения команды (вариант с перенаправлением):
ls | while read line
do
  # code
done

Вроде бы всё хорошо. Проблемы могут начаться в случае, когда во время чтения нужно изменять значения переменных. А именно, последний (и, кстати, наиболее часто используемый в случае, когда нужно обработать вывод команды, а не читать из файла) вариант приводит к созданию дочернего процесса (pipe же!), что приводит к тому, что все изменения переменных внутри тела цикла выполняются в подпроцессе и, как следствие, на процессе, в котором выполняется скрипт, не попадают. Это можно легко увидеть на следующем примере:
i=0; seq 1 3| while read line; do i=$(( $i + 1 )); done; echo $i
В bash и dash в результате будет выдан 0, в zsh и ksh (которые исполняют последний элемент пайплайна в текущем процессе в случае, если это shell built-in) — 3.
Обойти эту проблему можно несколькими способами. Один из них — использовать heredoc:
while read a b
do
  i=$(( $i + 1 ))
done <<EOF
`seq 1 3 | sed 's/^/1 /'`
EOF
echo $i
При этом, как можно видеть из примера выше, можно использовать произвольный пайплайн.
Очевидный недостаток этого решения — прежде, чем результат выполнения будет передан в цикл, он полностью будет получен. Это можно попытаться обойти, например, путём создания временного FIFO-файла:
fifofile=`mktemp`
rm "$fifofile"
mkfifo "$fifofile"

ls | sed 's/^/1 /' > "$fifofile" & # random command which output we need to parse
while read a b
do
  i=$(( $i + 1 ))
done < "$fifofile"
echo $i

rm "$fifofile"
Очевидно, что в данном случае строчка rm "$fifofile" будет выполнена после завершения цикла, что, по идее (так как read ждёт закрытия потока ввода), произойдёт только после завершения процесса, пишущего в FIFO и считывания из него всех данных.
Но всё же ощущается неаккуратность в виде наличия временных файлов. Тем более, что упражнение вида mktemp—rm—mkfifo теоретически может породить рейс. Можно попробовать соорудить конструкцию с созданием дескрипторов (like, exec 3<&0>&1):
exec 3<&0>&1

ls | sed 's/^/1 /' >&3 & # random command which output we need to parse
while read -u 3 a b
do
  i=$(( $i + 1 ))
done
echo $i

exec 3<&->&-

И, казалось бы, счастье есть: мы можем запихать произвольный пайплайн из процессов в этот дескриптор, а потом читать из него (или с помощью специального ключика у read, как в примере выше, или же просто <&3. Осталась одна маленькая проблема: если попытаться прибить скрипт до окончания его работы, то это ему ничуть не помешает. Посему, нужно повесить trap, который убивает дочерний процесс и завершает работу:
trap 'kill -9 $cpid; exit' TERM INT

exec 3<&0>&1

ls | sed 's/^/1 /' >&3 & # random command which output we need to parse
cpid=$!
while read -u 3 a b
do
  i=$(( $i + 1 ))
done
echo $i

exec 3<&->&-

Более аккуратного варианта как-то в голову не пришло. Если кто знает — поделитесь.

UPD. Таки приведённый вариант с дескрипторами работает только в zsh (не в dash). Буду думать, как его таки заимплементить.
esyr: (ночь)
Придумал зоймечательный алгоритм архивации: хранить пары смещение-длина, указывающие на куски в двоичной записи числа e. Или π. Или ещё какого трансцендентного.

Жаль, для хорошей степени сжатия потребуется совсем не полиномиальное время.
esyr: (Default)
Понадобилось мне как-то использовать moin для банальной задачи — получения из wiki-текста HTML. Казалось бы, задача должна решаться натравливанием какого-нибудь парсера-генератора. Но всё не так просто.
  • Да, у moin есть парсеры и генераторы, но они хотят в качестве параметра request, которого у меня, естественно, нет.
  • Хорошо, будет вам request. А как получить его? Правильно, использовать конструктор. Но вот незадача — в конструкторе обязательным параметром является конфигурация wiki instance. Которой у меня, естественно, нет.
  • Хорошо, воспользуемся DefaultConfig. Но им нельзя воспользоваться, поскольку там не прописана половина параметров. Например, место хранения кэшей. И пути к плагинам. Которых у меня, естественно, нет.
  • Хорошо, унаследуемся от DefaultConfig, пропишем пути в /tmp. Но config при инициализации проверяет наличие этих директорий. Которых у меня, естественно, нет.
  • Хорошо, создадим эти директории. Ура, мы можем сконвертировать wiki в HTML.

Вот так легко и просто использовать MoinMoin.

Итоговый код выложу как-нибудь на досуге, текущая версия работает только на патченном MoinMoin (который в куче случаев падает, хотя мог бы этого и не делать).
esyr: (Default)
«Кого-то губит любовь к алкоголю или к женщинам, а есыра погубит любовь к тернарному оператору» (по мотивам сказанного [livejournal.com profile] pourtous)

PS. В топике кусок реального кода с немного поменяными именами переменных, мда.
esyr: (Default)
В очередной раз осознал несостоятельность себя как программиста сегодня.
esyr: (Default)
Смена привычного стиля оформления комментариев в естественной речи с двух слешей на решётку наводит на мысли.
esyr: (Default)

Сижу, примус починяю макросы да действия для моина пишу...

Syntax

Jul. 14th, 2008 05:33 am
esyr: (ночь)
После С, жабы, жабоскрипта и ещё полудесятка языков как-то тяжко в питоне писать булевы константы с большой буквы.
esyr: (Default)
На нахождение ошибки вида
char buf[4];
...
buf[4] = 0;

Ушло времени больше, чем суммарно на нахождение всех предыдущих.
esyr: (ночь)
Как меня Наану позабавил. Есть у меня привычка после шэбэнга ставить пробел. Ну, там, миф есть такой, что некоторые древние шеллы не осиливали без пробела, да и вообще, красиво так magic получается четырёхбайтный: 0x2321202F. Эстетика, все дела.

Так вот, когда Наану это увидел, он чуть ли не заорал матом и затребовал это убрать. Вменяемого объяснения он так и не предоставил, сначала начал что-то говорить по поводу того, что так никто не пишет, но статистика быстро оказалась против него:
% grep '#! /' /usr/bin/* | wc -l
166
% grep '#!/' /usr/bin/* | wc -l 
685

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

Смешно. Наану ещё более фанатичен чем я, ибо даже свою точку зрения обосновать не смог (у меня были такие эфемерные сущности, как эстетика, 4-байтный magic и миф, но они таки были).

Чем-то мне это [livejournal.com profile] croco с его священной войной против юникода напомнило.
esyr: (Default)
>>> console.log($('#viewer.module').get().length);
0
>>> console.log($('.module#viewer').get().length);
1
esyr: (Default)
Наизвращаться в JS до того, что SpiderMonkey в двух случаях из трёх орёт uncaught exception: NS_ERROR_NOT_IMPLEMENTED это надо умудиться, мда…
esyr: (Default)

Практически ППКС.
esyr: (Default)
…думаю, сообщить Apple, что сайт http://localhost:1234 в сафари 3.04 бета отображается неправильно, или таки не стоит? А то у них кнопка такая заманчивая рядом с аддрессбаром…
esyr: (Default)
Хотел тут написать что-нибудь про JS, да как-то на ум ничего не приходит. Всё как-то обыденно: и определение функций inplace, и разный изврат на тему eval(), и всё жутко динамичное… И скомпоновать это так, чтобы получилось что-то технологичное, если и получается, то больших мозгов для этого использовать не надо. Мда.
esyr: (Default)
Допустим (а такое таки иногда случается), у нас есть ряд классов, (как это обычно и бывает) потомков одного класса, для которых удобно делать вещи в духе
Entity := TEntity.Create(TSubEntity1.Create(...), TSubEntity2.Create(...), ...);
...
Entity.Free;

То есть иметь конструктор, в котором можно проинициализировать состояние объекта. Причём объект у нас сложный и может включать другие объекты. Которые, в свою очередь, могут включать третьи, и так далее. И вся эта радость создаётся в одном операторе. Удобно.

Но при таком подходе возникает проблема… )
Выход из такого положения очевиден… )
Одним из возможных достаточно универсальных решений является использование RTTI… )
Быдлокод )
Тут комментарии на русском, но это исключительно для читабельности (и из-за того, что с английским я дружу плохо). Ни в коем случае не используйте неанглийские комментарии в коде.
Механизм действия сего деструктора )
Ограничения )
Собственно, мне это понадобилось потому, что я таким образом создаю сообщения, которые надо сериализовать в поток. Потом подумал, что это будет полезно не только мне, и решил написать об этом.

В следующий раз будет что-нибудь про XML (Save/Load объектов, загрузка UI) и/или версионинг, смотря что доведу до презентабельного состояния первым.
esyr: (ночь)
Повбывал бы за отсутствие документации по дельфёвому RTTI. То немного, что удалось вытащить из неё, это то, что проперши, точнее, TPropInfo может иметь тип, точнее, TTypeKind следующих видов:
tkUnknown, tkInteger, tkChar, tkEnumeration, tkFloat, tkString, tkSet, tkClass, tkMethod, tkWChar, tkLString, tkWString, tkVariant, tkArray, tkRecord, tkInterface, tkDynArray
Дальше надо уже лезть в TypInfo.pas и ныкаться по всяким форумам. Но вот из того же TypInfo.pas совершенно непонятно, как по тому, что у нас есть экземпляр записи TTypeInfo с TTypeKind tkRecord, то есть, проперти-запись, узнать поля этой записи. Или по массиву узнать его характеристики (хотя, для массива таки есть GetTypeData (у которого, кстати, превосходный исходнк:
function GetTypeData(TypeInfo: PTypeInfo): PTypeData;
asm
        { ->    EAX Pointer to type info }
        { <-    EAX Pointer to type data }
        {       it's really just to skip the kind and the name  }
        XOR     EDX,EDX
        MOV     DL,[EAX].TTypeInfo.Name.Byte[0]
        LEA     EAX,[EAX].TTypeInfo.Name[EDX+1]
end;
), который выдаёт TTypeData — монструозную структуру, в которой таки есть размер динамического массива и тип элементов, но у типа тип PPTypeInfo, и что пока с этим делать, не совсем понятно, хотя…). На самом деле, обе проблемы обходятся (первая — вложенным сериализуемым классом, структура которого повторяет структуру записи, вторая — сериализуемым списком сериализуемых объектов), но как-то коряво.
И ещё надо не забыть про версионинг, хотя ещё не уверен, нужен ли он тут.
esyr: (Default)
Что характерно, в имени жавайного пакетика может встречаться слово exception. А Eclipse его подсвечивает, хехе, как ключевое.

А ещё в жаве я не нашёл Pair<A, B>. Пришлось наколенный слабать. Несложно, конечно, но нехорошо лесопеды городить.
esyr: (Default)
Кто что может добавить/поправить?
Решил скопипастить из своей курсовой, всё равно у меня там перервод английской википеди+немного ссылко+чкть-чуть из других мест+ссылки.

Profile

esyr: (Default)
esyr

October 2010

S M T W T F S
     12
3456789
10111213141516
17181920212223
24252627282930
31      

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Sep. 20th, 2017 09:16 am
Powered by Dreamwidth Studios