Вот не знал, что кто-то умудрился. А вполне так получилось.
C#. Простой парсинг HTML Regerp’ом.
Да, предваряя камни, которые в меня полетят. Так делать нельзя, неправильно и вообще некузяво. Но что я буду делать, если нормальных парсеров под .NET Framework 2.0 уже net, а задача маленькая — найти все теги <a>
или <img>
и выдрать из них, соответственно, значение атрибутов href
или src
.
public List<string> ParseTags(string Tag, string Property) { List<string> listBuf = new List<string>(); Regex reHref = new Regex(@"(?inx) <" + Tag + @" \s [^>]*" + Property + @"\s* = \s*"+ @"(?<q> ['""] )"+ @"(?<url> [^""]+ )"+ @"\k<q>"+ @"[^>]* >"); foreach (Match match in reHref.Matches(HTMLPage)) { listBuf.Add(match.Groups["url"].ToString()); } return listBuf; }
Это немного видоизмененное решение (добавил возможность подставлять в регулярное выражение тег и атрибут) из одной статьи на Хабре. Заметка, как обычно, от склероза.
Плюс добавлена функция выбора из найденного, уже без всяких регулярных выражений, с помощью string.Contains(<строка>)
.
public List<string> Select(string Pattern, List<string> inputList) { List<string> selectList = new List<string>(); foreach (string s in inputList) { if (s.Contains(Pattern)) { selectList.Add(s); } } return selectList; }
C# Windows Forms. Использование ListView для логов, автоматическая прокрутка ListView, избавление от дрожания.
Иногда надо отображать пользователю ход процесса, т.е., что в данный момент наша программа делает. Лучше всего, на мой взгляд, для такого подходит компонент ListView
.
В него будем писать лог наших действий. Замутим тестовое приложение:
— Создадим форму с ListView
и кнопкой «Начать»
— По нажатию кнопки «Начать» запустим отдельный поток, который будет выводить нам числа от 1 до 100, и генерировать событие.
В коде или в конструкторе установим основные опции для ListView
. Нам нужно, чтобы он отображал все, как список. Ну так, как выводится лог в консоль. Устанавливаем соответствующие свойства:
View = Details
Теперь идем в конструктор, ищем опцию Columns
, и добавляем единственную колонку:
В появившемся окне все удаляем из поля Text
, жмем OK, смотрим на размер (Size
) ListWiev
, возвращаемся в редактирование колонок, и правим свойство Width
. Устанавливаем чуть меньше, чем размер самого ListWiev
.
Отладили, посмотрели чтоб было красиво? Ставим
HeaderStyle = None
(чтоб не отображался заголовок колонки, заголовки были убраны).
Несмотря на то, что все действия происходят в отдельном потоке, ListView
дергается и дрожит:
Для этого делаем новый контрол, наследник от
ListView
и в коде нового класса подправляем параметр отображения:
class MyListView:ListView { public MyListView() { this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); } }
Используем новый контрол вместо ListView
. Ничего не дрожит и не дергается.
При добавлении нового элемента:
Достаточно при добавлении в ListView
устанавливать свойство TopItem
в значение последнего элемента. Тогда у ListView
появится автоматическая прокрутка:
lvOut.TopItem = lvOut.Items[lvOut.Items.Count - 1]
;
C#. Работа с .ZIP архивами (подходит для старых .NET Framework’ов 3.5, 2.0)
Когда-то давно какой-то хороший человек написал библиотеку для работы с ZIP (а еще и Bzip2) архивами.
Приведу только простой пример использования — распаковка ZIP-архива в каталог:
public static bool UnzipToDir(string FileName,string UnzipDir) { ZipFile zip = null; try { zip = ZipFile.Read(FileName); foreach (ZipEntry e in zip) { e.Extract(UnzipDir, ExtractExistingFileAction.OverwriteSilently); // перезаписывать существующие } } catch (Exception ex) { ErrorMessage = ex.Message; return false; } return true; }
До использования, естественно, библиотеку надо подключить в References
‘ах и прописать using
:
using Ionic.Zip;
Работа с zip-архивами в .NET Framework 3.5 на C# Копия в PDF
1. Ссылка на Codeplex Archive
2. Скачать библиотеку с codernotes.ru
3. Копия архива Codeplex на nega.nz
4. Библиотека на Mega.nz
C#. Определить каталог пользователя.
Он же папка профиля пользователя, т.е., C:\Users\<имя пользователя>
, например C:\Users\Tolik
для пользователя Tolik
.
Проще всего посмотреть в переменную окружения USERPROFILE
:
Environment.GetEnvironmentVariable("USERPROFILE");
Для .NET Framework 4 и выше, путь к каталогу профиля пользователя добавлен в перечисление Environment.SpecialFolder
под именем UserProfile
. Таким образом, получить папку пользователя можно вот так:
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
static void Main() { string UserProfile = Environment.GetEnvironmentVariable("USERPROFILE"); MessageBox.Show(UserProfile, "User profile folder path", MessageBoxButtons.OK, MessageBoxIcon.Information); }
Хаос-магический программный визуализатор, исходники.
Когда-то давно написали такую вот ритуально—магическую программу. Леша захотел до-/перепилить, или добавить в программу новые объекты, попросил исходники. Еле нашел, но вроде все в кучу собрал.
Portable (ZIP-архив)
Установщик
Интерактивный скрипт для переключения VPN’ок
Старая версия скрипта Че-то решил переделать.
1. Заводим переменную для хранения каталога с конфигами:
CONFIGDIR="~/openvpn/configs"
2. Добавляем функции create_list()
и ask_list()
по этому вот рецепту
create_list() #$1 - dir, $2 - file mask { FOUNDLST="" for FLE in $(find $1 -maxdepth 1 -iname $2|sort); do if [ -n "$FLE" ]; then FOUNDLST="$FOUNDLST"`basename $FLE`"\n" fi done } ask_list() #$1 - list #$2 - header { LIST_BUF=$1 LIST_BUF="$LIST_BUF""Exit " LIST_BUF="$LIST_BUF""Down" LIST_BUF=`echo -e "$LIST_BUF"|sed 's/\n/ /'` PS3=$2 echo select LIST_RET in $LIST_BUF; do if [ -n "$LIST_RET" ];then break fi done }
Единственное что, в create_list()
добавляем сортировку (sort
), а в ask_list()
два пункта — для выхода из скрипта и для разрыва соединения.
3. Делаем функцию для разрыва соединения:
ovpn_down() { echo -n "Down connection..." CTR=0 pkill openvpn while [ "$CTR" -ne "1" ];do echo -n "." CTR=`ps ax|grep -c "openvpn"` sleep 1 done echo }
4. Основной скрипт.
4.1. Создаем список из файлов конфигов
4.2. Выводим список на экран и ожидаем ответа пользователя.
4.3. Выводим пользователю, что он выбрал.
4.5. Проверяем, не выбран ли выход — если выбран, завершаем работу скрипта.
4.6. Если выбран пункт Down, то вызываем функцию разрыва соединения и выходим.
create_list $CONFIGDIR "*.ovpn" ask_list $FOUNDLST "Select config: " echo "Selected: $LIST_RET" if [[ "$LIST_RET" == "Exit" ]]; then echo "Exitting..." exit 0 fi if [[ "$LIST_RET" == "Down" ]]; then ovpn_down exit 0 fi
4.7. Если до этого не вышли, завершаем прошлое соединение, если оно установлено:
ovpn_down
4.8. Поднимаем новое соединение (да, тут отправляю лог Openvpn на третий терминал):
echo "Up connection..."
openvpn --config "$CONFIGDIR/$LIST_RET" >/dev/tty3 &
4.9. Запускаю скрипт waiter на 10 секунд
~/scripts/waiter 10
1. На PasteBin
2. На GitHub
Автоматическое обновление пароля для vpnbook.com
На самом деле прошло куча времени, после того, как я заходил на vpnbook.com и пользовался их бесплатным vpn-сервисом. Ну так вот, есть проблема, сервис-то бесплатный, а пароль периодически менялся. Раньше было проще — пароль был на странице, и его можно было просто сграббить, а теперь нет — пароль нарисован на картинке.
1. Нам понадобится какой-то парсер HTML
2. Понадобится какая-нибудь распознавалка текста на картинке, тобишь OCR, поддерживающая режим командной строки, благо в линуксах есть их от слова, хоть дупой жуй. Я использовал самую известную и проверенную, Tesseract называется, распознает все на ура. Картинку с паролем, слава Ктулху, владельцы сервиса (пока) не зашумили и не испоганили, так что распознавание пройдет без дополнительного геморроя.
3. Для отладки можно показывать изображение перед распознаванием прямо в консоли, чтоб это работало, можно установить FIM (копия)
В Slackware проще всего установить его через sbopkg. В своих дистрах сами разбирайтесь.
1. Ставим sbopkg, если не стоит, с официального сайта или обновляем если стояла поросшая мхом версия со старым репозиторием в конфиге
2. Запускаем sbopkg В поиске (Search) вводим leptonica, и устанавливаем самую свежую версию. Это зависимость, т.е. библиотека, необходимая для Tesseract. Нашли — жмем Process и уходим курить.
3. Когда все скомпилировалось и поставилось, аналогичным образом ставим Tesseract.
1. Заводим необходимые переменные:
#!/bin/bash
VPNBOOKPAGE="https://www.vpnbook.com/"
WORKDIR="/tmp/vpnbook/"
HTMLFILE="vpnhtml.html"
PASSIMG="password.png"
AUTHPATH="~/openvpn/vpnbook/vpnbook.auth"
2. Перед скачиванием удаляем временный файлы и создаем рабочий каталог, если не существует (если существует, то ключ -p
в команде mkdir
поможет избежать ошибки):
rm "$WORKDIR$HTMLFILE" 2>/dev/null
rm "$WORKDIR$PASSIMG" 2>/dev/null
mkdir -p "$WORKDIR"
3. Скачиваем страницу с паролем:
echo -n "Get vpnbook page..."
wget -P "$WORKDIR" --default-page="$HTMLFILE" --header="Content-type: text/html" "$VPNBOOKPAGE" 2>/tmp/vpnpass.err.log
Примечание: Почему-то wget
всю информацию, вне зависимости от того, произошла ошибка, или все прошло штатно, выкидывает на stderr
, посему переопределяем в отдельный лог всю информацию из stderr
, чтоб экран не загаживала: 2>/tmp/vpnpass.err.log
4. Проверяем, загрузилось или нет:
if [[ ! -f "$WORKDIR$HTMLFILE" ]];then echo echo "Page not downloaded!" exit else echo "OK" fi
1. Вытаскиваем все ссылки на картинки со страницы
2. Отфильтровываем нужные grep'
ом: grep "password.php"
3. Выбираем одну (их там две одинаковых): head -n1
4. Заменяем пробел в ссылке на знак +, что понадобится для получения картинки (пробел в POST или GET запросе заменяется на +). Притворяемся браузером.
5. Объединяем это в одну команду, и сохраняем ссылку в переменную:
echo -n "Get password image..."
PASSLNK=`xidel -s --extract "//img/@src" "$WORKDIR$HTMLFILE"|grep "password.php"|head -n1|sed 's% %+%'`
6. Загружаем картинку себе:
wget "$VPNBOOKPAGE$PASSLNK" -O "$WORKDIR$PASSIMG" 2>>/tmp/vpnpass.err.log
7. Проверяем, успешно ли прошла загрузка:
if [[ ! -f "$WORKDIR$PASSIMG" ]];then echo echo "Image not downloaded!" exit else echo "OK" fi
8. Для отладки показываем картинку перед распознаванием, если был указан соответствующий ключ (-s
):
if [[ "$1" == "-s" ]];then fim "$WORKDIR$PASSIMG" fi
Для распознавания текста, нам придется воспользоваться OCR tesseract
. Поскольку текст на английском и довольно прост для распознавания, то из всей мощи Tesseract’а (а инструмент и правда очень крутой), мы воспользуемся самым простым вариантом — все оставим по умолчанию, а результат распознавания выведем на stdout
Примечание: Tesseract’у нужно обязательно указывать, куда выводить результат распознавания. Это второй параметр в команде.
Команда распознавания:
tesseract "$WORKDIR$PASSIMG" stdout
Сохраняем результат в переменную:
VP_PASSWORD=`tesseract "$WORKDIR$PASSIMG" stdout`
Выыодим полученный пароль на экран и сохраняем его в авторизационный файл для Openvpn:
echo -n "Recognize image..." VP_PASSWORD=`tesseract "$WORKDIR$PASSIMG" stdout` echo "OK" echo "Password: $VP_PASSWORD" if [ -z "$VP_PASSWORD" ]; then echo "Password is empty. Exitting!" exit fi echo -n "Update autorisation file $AUTHPATH..." echo "vpnbook" >"$AUTHPATH" echo -n "$VP_PASSWORD">>"$AUTHPATH" echo echo "Complete!"
Может совместить этот скрипт со старым скриптом, для обновления конфигов PPTP (новые конфиги делайте сами по образцу). Ссылка на старый скрипт
На PasteBin специально не кладу, поскольку там есть стукачи, которые доносят владельцам сервиса, что появился новый скрипт по выдиранию пароля. А по-русски владельцы сервиса читать не умеют. Да и на Гитхабе лежал скрипт четырехсотлетней давности, так что не догадаются, что обновился.
Обновление sbopkg и подключение репозитория от Slackware 14.2
Я по дурости поставил в новую слаку старый sbopkg, но поскольку ничего с него до сей поры не устанавливал, то как-то и не замечал. Понадобилось, а смотрю, репозиторий-то в нем от старой слаки.
Все делаем под root’ом
1. Сносим старый пакет через removepkg
, например (смотрите точное имя пакета средствами своей системы):
removepkg sbopkg-0.30.0-i486
2. Удаляем содержимое каталога /var/lib/sbopkg/
3. Качаем свежий sbopkg с официального сайта Прямая ссылка на пакет
4. Устанавливаем:
installpkg sbopkg-0.38.1-noarch-1_wsr.tgz
5. Идем в /etc/sbopkg
, видим там 2 файла sbopkg.conf
и sbopkg.conf.new
. Из sbopkg.conf
копируем (тем же mcedit
‘ом) в sbopkg.conf.new
значения переменных, если в старом конфиге их меняли. У меня, например, сменяно значение OUTPUT
, каталога, куда будет сохраняться готовый пакет:
export OUTPUT=${OUTPUT:-/root/sbopackets}
6. Переименовываем sbopkg.conf.new
в sbopkg.conf
7. Видел рекомендацию почистить кэш со скачанными исходниками (по умолчанию /var/cache/sbopkg
переменная SRCDIR
в конфиге), но хз. Я почистил, сохранив некоторые архивы.
8. Запускаем sbopkg
и в меню выбираем Sync, чтоб он синхронизировался с репозиторием. Новый репозиторий прописан в новом конфиге по умолчанию.
ФАНФАРЫ!
Автоматическое получение конфигов Openvpn для бесплатного VPN от vpnbook.com
Есть относительно неплохой бесплатный сервис VPN vpnbook.com, мы про него когда-то давно писали, а я одно время даже активно пользовался, пока меня не задолбали некоторые ограничения, и я не перешел на лучший и более надежный в плане безопасности Riseup, но в качестве резерва, почему бы не иметь и его? Заодно и знакомый попросил его настроить.
В общем, пошел я на сайт, а там все изменилось, появились и периодически добавляются новые сервера, старые подохли, в общем контора активно цветет и пахнет.
Так вот, на случай появления новых серверов, придется идти на сайт, скачивать конфиги, при необходимости добавлять свои параметры, и т.д. А зачем это каждый раз делать руками, если можно автоматизировать?
1. Вытащить с сайта список конфигов
2. Скачать архивы конфигов на локальный компьютер и распаковать их
3. Автоматически добавить в конфиг дополнительные параметры, например изменить уровень script-security
и добавить пользовательские скрипты, выполняющиеся при соединении и разрыве соединения с сервером, и т.д. Подробности тут или тут
4. Конфиги для каждого сервера поставляются в нескольких вариантах, для соединения по разным портам, например TCP 443, TCP 80, UDP 25000, UDP 53. Сервера различаются по странам. Соответственно, надо предусмотреть возможность выбора всех или определенных конфигов.
Нам понадобится какой-нибудь парсер HTML. Я использую xidel
, о котором недавно писал
1. Добавляем в начало скрипта необходимые переменные:
VPNBOOKPAGE="https://www.vpnbook.com/"
WORKDIR="/tmp/vpnbook/"
UNPDIR="/tmp/vpnbook/unpack/"
HTMLFILE="vpnhtml.html"
Страница, с которой будем выдирать ссылки на архивы, рабочий каталог скрипта, каталог, куда будем распаковывать архивы и имя файла, под которым сохраним HTML-страницу сайта с нужными данными.
2. Предусматриваем возможность удалить каталог с распакованными конфигами (если пользователь запустит скрипт с ключом -с
):
if [[ "$1" == "-c" ]]; then echo "Cleaning unpack directory..." rm -rf "$UNPDIR" fi
3. Удаляем ранее сохраненный HTML-файл (иначе новые wget
будет сохранять под именами vpnhtml.html.1
, vpnhtml.html.2
и т.д.) и создаем рабочий каталог и каталог для распаковки архивов. Путь будет создан со всеми подкаталогами, если он ранее не существовал. Если каталог уже существовал, то никакой ошибки не будет.
rm "$WORKDIR$HTMLFILE"
mkdir -p "$WORKDIR"
mkdir -p "$UNPDIR"
Далее под катом
Отображение картинок в консоли Linux
Задумался тут, можно ли показать изображение в консоли Linux без использования X-Server’а. Ведь в современных Линуксах консоль, по большей части, только маскируются под текстовую, а на самом деле, с определенного этапа загрузки ОС, она вполне себе графическая, и фреймбуфер у них есть, и все прочее для отображения картинки. Шрифты же она отображает, причем не как в DOS, где в консоли никакого графического режима по умолчанию нет, и единственный шрифт 80×25 для VGA-режима и 40×25 для EGA (о-о-о-чень старые мониторы и видеочипы), ЕМНИС.
В Linux наоборот, надо еще пошаманить, чтобы сэмулировать режим VGA в «голой» консоли без иксов. Если не шаманить, то наоборот, может получиться как-то так:

Мелко, противно, нихрена не видно
Справедливости ради, в DOS есть и графические режимы, и даже софт для отображения картинок, но, фактически отображение будет не совсем «в консоли», программа должна будет переключить видеоадаптер в графический режим, и там уже сама как-то справляться с изображениями.
Вернемся к Linux. Итак, консоль вполне себе графическая, так есть ли софт? Как выяснилось, есть.
Называется программа FIM. Программа небольшая, поддерживает основные форматы (BMP, GIF, JPEG, png, tiff) и некоторые другие (PPhotoCD, ppm, XWD), а для остальных она пытается использовать ImageMagick. Программа основана на Fbi (framebuffer imageviewer — это нечто вроде печально известного Vim, только для работы с изображениями в консоли).
В зависимости от того, где она была запущена, программа использует разные механизмы отображения графики:
— если она выполняется в эмуляторе терминала под иксами, то использует библиотеку SDL или imlib2. Впрочем, в иксах, лично у меня, fim смухлевал. В том же самом терминале рисовать не стал, а создал отдельное окно.
— если запущена в «голой» консоли без иксов, использует консольный фреймбуфер
— и, что довольно забавно, если попытаться запустить ее на терминале, который графику не поддерживает (например, через PuTTY), то программа преобразует изображение в ASCII-арт, ну тут уж, что называется, как получится.
Для Debian/Ubuntu и подобных им дистрибутивов есть готовый пакет, для Slackware пришлось собирать из исходников, впрочем, у меня собралось с первого раза.
fim <имя файла 1> [имя файла 2] [имя файла 3...]
— для просмотра одного или нескольких файлов.
fim -R <каталог>
, например, fim -R ~/Pictures/
— для просмотра изображений в каталоге.
n — следующий файл
p — предыдущий
+ — увеличить
— — уменьшить
r — поворот
m — отзеркалить
f — отзеркалить и перевернуть вверх ногами
q, ESC — выход
На самом деле у утилиты довольно много возможностей, есть командный режим, как у Vim, в котором изображение можно редактировать, подробное описание всех возможностей — в мануале на официальном сайте.
Котик в «голой» консоли
А вот в иксах он смухлевал, хотя котика нарисовал
Псевдографический котик в текстовом терминале. Довольно ничего получилось.
Ссылки
xidel, крохотный парсер HTML, XML, JSON
Понадобилось тут быстро и качественно выдрать из HTMLки ссылки и картинки.
Наткнулся на довольно интересный инструмент. Называется xidel, и умеет вытаскивать данные не только из HTML, но также из XML, CSS, JSON, в общем штука получается довольно универсальная. Еще один плюс — кросплатформенность. На сайте есть готовые бинарники под Windows, Linux, пакет для Debian. Все вышеперечисленное, что очень приятно, есть в версиях, как для x86, так и для x64. Также имеются версии для Android ARM и Mac OS 10.8. Открыт и исходный код. Утилита, что хорошо, маленькая, самая большая версия для Android — 2Мб, остальные еще меньше.
Брать исходный файл программа может, как из сохраненной на диск страницы, так и непосредственно с сайта.
На самом деле, инструкция там довольно большая, покажу только самые простые вещи.
Выдираем все адреса ссылок с главной страницы:
xidel -s --extract "//a/@href" "http://tolik-punkoff.com"
Выдираем адреса изображений:
xidel -s --extract "//img/@src" "http://tolik-punkoff.com"
То же самое с сохраненной предварительно на диск страницей:
wget -P "/tmp" --default-page="test.html" --header="Content-type: text/html" "http://tolik-punkoff.com"
xidel -s --extract "//a/@href" "/tmp/test.html"
wget -P "/tmp" --default-page="test.html" --header="Content-type: text/html" "http://tolik-punkoff.com"
xidel -s --extract "//img/@src" "/tmp/test.html"
Скачать
NodeJS для Slackware 14.2
Ох и запарился я ее собирать… Не, собралась автоматом, просто долго. А готовые пакеты у них на сайте почему-то только под Linux x64. Поэтому, чтоб не пролюбить пакеты:
На всякий случай еще и исходники сохраню.
Смешно, из-за нее не так давно умудрился уронить 12 слакварь, точнее Absolute Linux, который был на ней основан, вертелся-крутился года три и никого не трогал, так и перешел на 14-ую.
Использование переменных из bash-скрипта в sed
Вроде невелика проблема, а вопросы вызывает. Понятно, что вот так работать не будет:
VAR1="Nado naiti"
VAR2="Nado zamenit'"
sed 's/$VAR1/$VAR2'
т.к. одинарные кавычки в команде sed
все закэранируют, и sed
будет искать черти что и с боку бантик.
1. Поменять одинарные кавычки на двойные.
2. Поменять sed’овский разделитель слэш (/
) на что-нибудь другое, например на знак %
(Уникальность программы sed в том, что она позволяет использовать любой разделитель, например знак подчеркивания)
VAR1="Nado naiti"
VAR2="Nado zamenit'"
sed "s%$VAR1%$VAR2"
Добавление строки в начало файла из предыдущей заметки. Строка содержится в переменной $FIRSTSTRING
:
sed -i -e "1 s%^%$FIRSTSTRING\n%" file.txt
Замена строки, начинающейся с любого количества пробелов и/или со строки из переменной $START
на строку, содержащуюся в переменной $REPLACE
:
sed -i "s%^ *$START.*%$REPLACE%" file.txt
Вставить строку в начало текстового файла в Linux
echo "First line" >newfile.txt
cat oldfile.txt >>newfile.txt
mv newfile.txt oldfile.txt
sed -i -e '1 s/^/First line\n/' file.txt
Замена концов строк Windows/DOS (CR LF \r \n) на Linux (LF \n) в bash
Проще всего сделать sed’ом.
В том же самом файле (добавляем параметр командной строки -i
):
sed -i 's/\r$//' file.txt
В другой файл:
cat winfile.txt | sed -i 's/\r$//' >linuxfile.txt
NSIS: продолжение установки после перезагрузки.
Например, у нас есть софтина, которая в процессе своей установки требует перезагрузку, после чего доустанавливается. Например, софт устанавливает свой драйвер, обновление, или же регистрирует системный сервис. Как реализовать инсталлятор для такой программы?
Изначально я хотел обойтись параметрами командной строки, добавляемыми при запуске установщика, но с ними произошла жопа, поэтому будем действовать более надежными методами.
0. Проверяем наличие уникального ключа Реестра, сигнализирующего о том, что надо выполнить вторую часть установки (после перезагрузки):
DetailPrint "Read After Reboot flag..."
ReadRegStr $R0 HKCU "Software\Microsoft\Windows\CurrentVersion\"
"${APPNAME}_afterreboot"
StrCmp "$R0" "1" AfterReboot
1. Производим все действия, которые необходимо произвести до перезагрузки (устанавливаем драйвера, регистрируем DLL и т.д.)
2. Записываем в однократную автозагрузку (ключ Реестра RunOnce
) наш инсталлятор, путь к exe файлу инсталлятора, который можно взять из переменной $EXEPATH
.
Автозагрузку прописываем для текущего пользователя (пользователя, запустившего установщик), т.е. в ключ HKEY_CURRENT_USER
.
WriteRegStr HKCU
"Software\Microsoft\Windows\CurrentVersion\RunOnce"
"${APPNAME}" "$EXEPATH"
Примечание: В RunOnce
могут записаться программы, которые требуется выполнить однократно при загрузке системы. После выполнения программ, ключ RunOnce
очищается автоматически, что отличает его от ключа Run
, где данные не очищаются, и его можно использовать, как постоянную автозагрузку.
3. Устанавливаем уникальный флаг, по которому будем определять, что инсталлятор был запущен после перезагрузки, например, таким образом:
DetailPrint "Write After Reboot flag..."
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\"
"${APPNAME}_afterreboot" "1"
4. Выдаем запрос на немедленную перезагрузку:
DetailPrint "Reboot request."
MessageBox MB_YESNO|MB_ICONINFORMATION
"Installation will be cobntinue after reboot. Press OK to reboot now." IDYES RebootID
Если пользователь ответил «Yes
«, сразу перезагружаемся:
RebootID: DetailPrint "Rebooting..." Reboot
Если нет, ждем перезагрузки вручную:
DetailPrint "Installation continue if user restart system."
Goto SecEnd
5. После перезагрузки удаляем флаг (проверив его наличие, см выше):
DetailPrint "Delete After Reboot flag..."
DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\"
"${APPNAME}_afterreboot"
6. И продолжаем установку…
DetailPrint "Continue install after reboot..."
Глюк в NSIS: проверка параметров командной строки инсталлятора не работает
Вот серьезно, бьюсь (головой об стену) уже третий день, ну не работает функция GetOptions
, так, как заявлено в NSIS Wiki, уже и по колесам стучал, и фары протирал, в смысле просто тупо копировал код из примера в тестовый инсталлятор, и еще десяток написал, перепробовав все что можно и нельзя, ну не выходит каменный цветок, хоть тресни. Функция в любом случае выдает, либо что никаких ошибок не случилось, для следующего кода, соответственно, всегда получается found:
Section ${GetOptions} "/S /T" "/T" $R0 IfErrors 0 +2 MessageBox MB_OK "Not found" IDOK +2 MessageBox MB_OK "Found" SectionEnd
Либо, для следующего кода всегда остается значение по умолчанию, даже если в командной строке явно задано иное:
Section ${GetOptions} "/AR=N" "/AR=" $R0 DetailPrint "R0: $R0" SectionEnd
Например, выполняешь TestInstaller.exe /AR=Y
, все равно в переменной $R0
оказывается N
Такие дела.
Переопределение вывода на другой терминал в Linux
Пришли сегодня ко мне с одной задачкой, мол есть у нас программка, которая висит в фоне и периодически выводит данные в консоль. Неудобно оператору работать, либо что-то другое делать, либо ничего не делать, лишь в консоль смотреть. Даже отдельный комп думаем программке выделить, чтоб она на нем крутилась-вертелась. И нельзя ли так сделать, чтоб программку на другом терминале запустить, чтоб можно было по Ctrl+Alt+F[номер] переключаться, и за состоянием программки смотреть?
Вот запустить нельзя, без особого бубна, а вывод переопределить, всегда пожалуйста.
Можно пользуясь стандартным перенаправлением ввода-вывода в Linux, заставить программу или скрипт отправлять сообщения на другой терминал. Пусть программка будет называться tscript
. За терминалы в Linux отвечают устройства /dev/tty*
, например, /dev/tty2
отвечает за терминал, вызываемый по Ctrl+Alt+F2.
Например, чтобы программа переопределяла вывод на /dev/tty2
, запускаем ее таким образом:
tscript >/dev/tty2
Можно отправить на другой терминал только вывод сообщений об ошибках:
tscript 2>/dev/tty2
Чтобы программа работала в фоне, а на том терминале, с которого мы ее запустили, можно было продолжить работу, добавляем после команды знак &
:
./tscript >/dev/tty2 &
Пишем тестовый скрипт, который, скажем, будет бесконечно выводить на консоль случайное шестнадцатиричное число раз в секунду:
#!/bin/bash SEC=1 echo "Test script, write to STDOUT random number after $SEC sec." while [ 1 -eq 1 ];do sleep $SEC printf 'Number: %x\n' $RANDOM done
Пишем скрипт, который будет убивать тестовый:
#!/bin/bash
echo "Kill test script..."
pkill tscript
Пишем запускающий скрипт, в котором вывод тестового скрипта переопределяется на терминал tty2
:
#!/bin/bash
TERMNO=2
echo "Send tscript output to terminal #$TERMNO"
./tscript >/dev/tty$TERMNO &
Запускаем тестовый скрипт на текущем терминале:

Выполняем запускающий скрипт:

Состояние tty1
Вывод на tty2
Исходники примера
NSIS: Совсем коротко про секции
Секции — это удобный механизм, позволяющий обеспечить пользователю выбор компонентов программы, если такие присутствуют. В каждой секции можно создавать свои ярлыки, распаковывать файлы, и производить любые другие действия, практически независимо от других секций. Естественно, значения переменных, измененные в одной секции, в других тоже будут изменены, потому что в NSIS все переменные глобальные.
Для самого простого выбора компонентов в NSIS, необходимо вставить в скрипт, перед, собственно, описанием секции, следующий код:
ComponentText "Какой-то текст"
, например:
ComponentText "Choose which features of ${APPNAMEANDVERSION} you want to install."
Естественно, ${APPNAMEANDVERSION}
должна быть заранее определена:
!define APPNAME "SectionsExample"
!define APPNAMEANDVERSION " SectionsExample 0.1"

Окно инсталлятора с выбором компонентов
В любом NSIS-скрипте должна быть создана хотя бы одна секция, иначе компилятор будет ругаться, и файл установщика не создаст. В самом простом случае, когда не требуется выбор компонентов, создается единственная секция без названия:
Section DetailPrint "Hello, world!" SectionEnd

Примечание: После конструкции Section
идет имя секции, заключенное в кавычки. Если кавычки пропустить, то имя секции будет некорректным, и неверно отобразится в окне выбора компонентов. Попробуйте вставить следующий код в пример, и посмотрите, как он будет работать. Ссылка на пример в конце заметки.
Section Component 4 ; Wrong section description SetOverwrite on DetailPrint "Component #4 installing..." SectionEnd
Для чего? Например, у нас есть программа, у которой, в свою очередь есть основные компоненты, например экзешник и DLL, а также дополнительные, которые можно устанавливать, а можно и не устанавливать. И если уж пользователь хочет поставить наше приложение, то он должен установить хотя бы основные компоненты.
Для того, чтобы заблокировать чекбокс, прописываем в начале секции конструкцию:
SectionIn RO
Section "Main Program and components" ; Checkbox select and disable user changes SectionIn RO SetOverwrite on DetailPrint "Main program installing..." SectionEnd
Для этого ничего делать не надо, только определить секцию с именем в кавычках и дефольными настройками. Пользователь может деактивировать checkbox (снять галочку) в окне выбора компонентов.
Section "Component #2" ; Checkbox enabled by default & user will change it state SetOverwrite on DetailPrint "Component #2 installing..." SectionEnd
Наверное, самый частый вопрос, задаваемый, что в рунете, что в Интернете вообще, по поводу NSIS. Так вот, ларчик открывается просто. Достаточно после Section
поставить специальный флаг /o
.
Пользователь также сможет активировать checkbox (галочку), если ему нужно будет установить данный компонент.
Section /o "Component #3" ; Checkbox disabled by default & user will change it state SetOverwrite on DetailPrint "Component #3 installing..." SectionEnd
Такие секции не будут отображены в окне выбора компонентов. Их названия пишутся без кавычек и без пробела, а перед названием ставится знак «-
«. Код в таких секциях будет выполнен в любом случае, независимо от желания пользователя:
Section -HiddenSection DetailPrint "This is a hidden section" DetailPrint "This code running anyway." SectionEnd
К ним, наверное, относится одна — Uninstall
, ну и еще не совсем секция, а встроенная функция, которую можно переопределить, дописав свой код, т.е. что-то типа обработчика событий в «больших» языках, например в C#
О секции Uninstall
и рассказывать особо не надо, кроме ремарки, что в секции Uninstall
«забываются» все значения глобальных переменных и значение переменной $INSTDIR