Интерактивный скрипт, устанавливающий Syslinux

А так же ISO-образ Acronis True Image и Puppy Slacko.

Преамбула

Попросили превратить мою заметку про то, как можно пользоваться Acronis True Image без его акронисовского «восстановления при загрузке», превратить в интерактивный скрипт, который делает все то, что описано в заметке, но сам, задавая пользователю наводящие вопросы.

Сделал, чо. Правда, скрипт, наверняка, дичайший быдлокод, но работает без ошибок. Единственное что, предварительно надо создать основной раздел ext2/ext3 на жестком диске, и он должен идти первым. Потом установить винды, сделать линуксовый раздел активным, а потом уже запускать скрипт со всеми потрохами.

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

Основная заметка

Эмуляция восстановления при загрузке Acronis True Image с помощью syslinux/extlinux Копия

Список заметок по теме

1. Создание списков (из файлов в каталоге) Копия
2. Простой интерактив в bash-скриптах (запрос Y/N и запрос строки) Копия
3. Простой интерактив в bash-скриптах (меню, списки) Копия
4. Проверка, установлен ли флаг раздела «активный» Копия
5. Определение файловой системы раздела диска в Linux Копия
6. Поиск загрузчика Windows Копия
7. Получение MBR ID и номера раздела, для передачи управления другому загрузчику Копия
8. Число или строка в переменной BASH Копия

Скрипт и готовые «пакеты» с Syslinux и модулями

На GitHub

Поскольку, наверняка набыдлокодил, то исправления и дополнения приветствуются.

Пемза

Продолжаем заниматься прикладным геоложеством, тем более, что этот минерал в не таком далеком прошлом и правда прикладывали, даже с силой, можно сказать, терли об свой организм. А точнее, использовали вместо скраба. Итак, знакомьтесь, пемза — пепел давно потухшего вулкана. И этот образец откопал я лично на даче у друга, так что я прям геолог, геолог прям. Примерно вот по этим координатам: 62.257657, 34.439260. Могу налюбить вас эдак на километров 10, тому ще GPS-навигатор я благополучно в городе оставил, а теперь восстанавливаю поездку по гугл-картам. Вроде, нашел похожее на правду озеро. Если что, поеду еще раз, подкорректирую координаты.
Особенность обработки участка в том, что у них на огороде нет привозной земли от слова совсем, так что, что было из огорода выкопано, то там и лежало с тех времен, когда в Карелии еще были действующие вулканы. Ближайшие к точке в Лижме, и чуть дальше — в Гирвасе:

Лижма, если по дороге, ~ в 19 км, если спрямить, наверное, будет километров 15, т.е. для вулкана фигня — доплюнуть мог.

До более известного Гирвасского вулкана — напрямую ~55 км, еще и через озеро Сандал. Мог он туда доплюнуть или нет, не ведаю.

Сам минерал легкий, пористый (навскидку, весит примерно столько же, сколько гораздо меньший по объему кусочек шунгита), у него, наверное, внутри еще есть газы той земной атмосферы :). А еще он легко разделяется на довольно толстые пластины. Этот кусок я не трогал, но над другими мы экспериментировали, плюс находили практически ровные пластины пемзы в земле.




Еще фото под катом

Другие фото:

1 2 3 4 5 6 7

Так что вот, такая занимательная геология, не отходя от дачи.

Раритетная метеорологическая таблица (для определения видимости)

Ездили мы на днях с поэтами в славный город С., где поэты выступали, а я зарулил на местную метеостанцию и сфотографировал там раритетную таблицу для определения видимости. Собственно, таблицу меня запрягли осовременивать, пришлось делать ее копию в Excel’е, а таблица древнючая — 70х годов прошлого века. Так что сегодня у нас артерфакт метеорологический.

Лицевая сторона:



Другие фото

1 2 3

Оборотная сторона:

Еще фото под катом

Удаление кривого активатора ODIN.

Преамбула

Позвали тут в дружественную конторку, где после очередных обновлений перестал работать какой-то очередной русский инновационный криптопровайдер (не Крипто Про, с ним вроде такой беды не случалось). Оказалось, программулина конфликтовала с кривым активатором ODIN, да-да, винда почему-то тоже оказалась нелицензионной, несмотря на государственный статус этой самой конторки. Пришлось удалять.
А активатор кривой тому ще подсовывает в винду патченное ядро, дабы установить драйвер без цифровой подписи, нужный для эмуляции таблицы SLIC.

Простой способ (который не сработал)

На рутрекере, кстати, в хорошей и обстоятельной теме про активацию семерки, предлагали просто создать BAT-файл со следующим содержимым, и запустить его с правами администратора, после чего перезагрузиться:

del "%windir%\system32\drivers\oem-drv64.sys"
del "%windir%\system32\xNtKrnl.exe"
del "%windir%\system32\xOsLoad.exe"
del "%windir%\System32\ru-RU\xOsLoad.exe.mui"
del "%windir%\System32\en-US\xOsLoad.exe.mui"
%windir%\system32\bcdedit.exe /set {current} path \Windows\system32\winload.exe
%windir%\system32\bcdedit.exe /deletevalue {current} kernel
%windir%\system32\bcdedit.exe /deletevalue {current} nointegritychecks
%windir%\system32\bcdedit.exe /deletevalue {current} custom:26000027
reg delete HKLM\SYSTEM\CurrentControlSet\services\oem-drv64 /va /f

Кому-то может и поможет, но мне не повезло, файлы активатора не удалились, reg delete не сработал, потому я просто нашел в дистрибутиве их виды «автоматический установщик» активатора, и просто провернул последовательность действий в обратном порядке.

Удаление параметров Реестра и конфигурации загрузчика

Получился такой вот CMD-файл
В каталоге с этим батником должен быть подкаталог data, со следующим содержимым:
1. Утилита SetACL.exe, которая будет менять права доступа к ключам Реестра, и восстанавливать их после редактирования. Утилиту взял из того же дистрибутива.
2. Утилитка sleep, но это так, для красоты, моя прихоть.
3. Файлы Реестра (*.reg) для x86 и x64 ОС, в которых прописано, какие ключи удалять anti-oem-drv64.reg anti-oem-drv86.reg

Далее я сделал RAR-SFX с таким сценарием:
;Расположенный ниже комментарий содержит команды SFX-сценария

Setup=Deactivator.cmd
TempMode="Удалить активатор?","Деактиватор"
Silent=1
Overwrite=1

И поставил галочку в дополнительных параметрах SFX, на запрос административного доступа.

Удаление файлов активатора

После перезагрузки можно удалить файлы активатора, таким вот CMD-файлом.

@ rem echo Этот файл должен быть запущен с правами администратора и после выполнения Deactivator'а
@ rem echo Чтобы окончательно удалить следы активатора нажмите любую клавишу, иначе CTRL+C!
@ rem pause

DEL "%windir%\system32\drivers\oem-drv64.sys"
DEL "%windir%\system32\xNtKrnl.exe"
DEL "%windir%\system32\xOsLoad.exe"
DEL "%windir%\System32\ru-RU\xOsLoad.exe.mui"
DEL "%windir%\System32\en-US\xOsLoad.exe.mui"
DEL "%windir%\system32\drivers\oem-drv86.sys"

@echo "Clean complete."
@pause

И SFX-сценарий к нему:

;Расположенный ниже комментарий содержит команды SFX-сценария

Setup=Cleaner.cmd
TempMode="Выполняйте только после исполнения Deactivator'а, если хотите окончательно удалить следы активации","Окончательная очистка"
Silent=1
Overwrite=1

Скачать

1. Deactivator.exe
2. Cleaner.exe

Репозиторий на GitHub

Большая статья о механизмах активации Windows 7

На Rutracker.org Копия в PDF

Шунгит

Сегодня в номере геологический атерфакт, образец породы шунгита, собственно, из месторождения близ Шуньги, деревни, которая и дала название минералу. Это практически сверхчистый образец, с повышенным содержанием фуллеренов, для использования в медицине и быту. Да, из него можно сделать фильтр для воды, но я лично не хочу портить камень, поэтому просто помещаю его в банку с водой на ночь, если мне вдруг хочется шунгитовой водички.
Если вдруг захотите себе такой же (хоть кило) — добро пожаловать в редакционный телеграм, у нас прямые поставки из Шуньги, а доставить можем по всему СНГ и РФ.


Остальные фото под катом

Передача управления другому загрузчику по MBR ID в Syslinux.

Преамбула

Раз уж в прошлой заметке зашла речь про chainloading, т.е. передачу управления другому загрузчику из Syslinux, был разобран стандартный способ указания загрузчика в виде записи hdX Y, и определен минус этого способа, то можно рассказать и про устранение этого минуса.

Согласно спецификации, управление другому загрузчику можно передать не только указав номер диска и раздела, но и в следующем формате:

mbr:<id> [<partition>]

где:
<id> - уникальный MBR ID
<partition> - номер раздела жесткого диска

Схема нумерации разделов жесткого диска

Эта схема, конечно, для предыдущего случая, но разделы (а не диски), в обоих случаях нумеруются одинаково. А вот вместо hd0 (hd1, hd2…) будет mbr:<id>.

Пример конфига

Вот часть измененного конфига syslinux.cfg, где chainloading используется для загрузки Windows со второго раздела на первом жестком диске, только теперь жесткий диск определяется не по номеру, а по MBR ID:

LABEL windows
   menu label Microsoft Windows 7
   kernel modules/chain.c32
   append mbr:0x31c5dff2 2

Получение номера раздела, MBR ID и формирование записи конфигурации для загрузчика Syslinux

Сделал весь процесс в отдельной функции get_slid(), куда первым параметром передается имя устройства (с номером раздела или без), например, /dev/sda2.

1. Получим имя устройства без пути:

T_BN=`basename $1`

2. Получим номер раздела, удалив из начала имени все латинские буквы:

T_VOLNUM=`echo "$T_BN" | sed 's/^[a-z]*//'`

3. Получим имя устройства, с полным путем, но без номера раздела:

T_DSKNAM=`echo "$1"|sed 's/[0-9]\+$//'`

4. Проверим, не получилась ли пустая строка (может случиться, если в первый параметр что-то не то положили):

if [ -z "$T_DSKNAM" ]; then
    return 1 #error
fi

5. Получаем идентификатор MBR, способ указан в руководстве по chain.c32 [1]:

T_MBRID=`hexdump -s 440 -n 4 -e '"0x%08x\n"' "$T_DSKNAM"`

т.е. hexdump читает из MBR устройства 4 байта идентификатора, и выдает их в виде строки требуемого формата.

6. Формируем строку для конфигурации Syslinux:

SL_ID="mbr:$T_MBRID $T_VOLNUM"

7. Пример вызова функции:

if [ -z "$1" ]; then
    echo "Use "`basename $0` "<device>"
    exit
fi

get_slid "$1"

if [ "$?" -ne 0 ];then
    echo "Error!"
else
    echo "$1: $SL_ID"
fi

Скрипт целиком

На PasteBin
На GitHub

Источники

1. Comboot/chain.c32
2. Syslinux (Русский)

Преобразование имени раздела и устройства в формат SYSLINUX

Преамбула

Меня спрашивают, а где на практике можно применить «номер буквы в алфавите», про получение которого в bash-скрипте было недавно написано. Вот пример такого практического применения. Известно, что в Linux дисковые устройства представлены в виде /dev/sda, /dev/sdb, /dev/sdc и т.д., а разделы диска в виде /dev/sda1, /dev/sda2
SYSLINUX, точнее его модуль chain.c32, который может передавать управление другим загрузчикам, использует другой формат:

hdD P
где:
D — номер устройства (диска) в BIOS
P — номер раздела на диске
Отсчет дисков ведется с 0, разделов — с 1 (0 — главная загрузочная запись диска)
Например, hd0 2 — загрузка должна производиться со 2 раздела первого диска, hd1 1 — с 1 раздела второго жесткого диска, hd3 0 — необходимо передать управление главной загрузочной записи (MBR) четвертого диска.

Вот часть конфига syslinux.cfg, где chainloading используется для загрузки Windows со второго раздела на первом жестком диске:

LABEL windows
   menu label Microsoft Windows 7
   kernel modules/chain.c32
   append hd0 2

Некоторые минусы

— Минус, связанный с BIOS. Если вдруг порядок устройств в BIOS поменяется, то загрузчик SYSLINUX «заблудится» и попытается передать управление не туда.
— Некоторые линуксы меняют порядок именования жестких дисков, т.е. /dev/hda может и не соответствовать первому загрузочному диску. Тут уже зависит от конкретного дистрибутива.

Первый минуса можно избежать, используя вместо номера диска MBR ID, но это уже тема для отдельной заметки.

Получаем ID для chain.c32

Я организовал это в отдельной функции get_sysl_hd(), чтобы было удобно утащить в другой скрипт, буде понадобится. Первый параметр функции — имя устройства, например, /dev/sda1

1. Получаем имя устройства без пути к нему.
T_DN=`basename $1`

2. Можно проверить, соответствует ли имя устройства формату имени дисков, а то вдруг нам CD-ROM подсунули 🙂
Имя диска начинается с первой буквы s или h на некоторых пожилых дистрибутивах, далее следует буква d, далее — латинская буква a-z, потом могут следовать цифры (номера разделов). Можно сообразить вот такое простенькое регулярное выражение:

^[sh]d[a-z][1-9]*$

Далее пропускаем результат работы basename через grep, и проверяем выхлоп в переменной. Если переменная пустая, подсунули что-то не то.

T_DN=`basename $1|grep '^[sh]d[a-z][1-9]*$'`
if [ -z "$T_DN" ]; then
	return 1
fi

Но на самом деле, эта проверка не очень-то и нужна, можно пропустить этот пункт

3. Получаем третью букву в имени диска с помощью команды expr:
expr substr pos len

где:
substr — операция получения подстроки
pos — позиция символа в строке (отсчет ведется с единицы)
len — длина подстроки

T_3LET=`expr substr $T_DN 3 1`

4. Получаем номер буквы в алфавите. Я воспользовался вторым копия из ранее описанных способов.

S_CODE=`printf '%d' \'$T_3LET`
A_CODE=`printf '%d' \'a`
SYSL_ID="hd"`expr $S_CODE - $A_CODE`

5. Получим номер раздела, удалив sed‘ом все латинские буквы с начала имени устройства в переменной $T_DN:

T_VOLNUM=`echo "$T_DN" | sed 's/^[a-z]*//'`
if [ -z "$T_VOLNUM" ]; then
	T_VOLNUM=0
fi

Если переменная окажется пустой, значит нам подсунули устройство, без указания раздела — необходимо сослаться на MBR. Присваиваем T_VOLNUM значение 0.

6. Добавляем полученные данные в переменную SYSL_ID

SYSL_ID="$SYSL_ID $T_VOLNUM"

7. Пример вызова функции:

if [ -z "$1" ]; then
    echo "Use "`basename $0` "<device>"
    exit
fi

get_sysl_hd "$1"

if [ $? -ne 0 ];then
    echo "Bad device name!"
else
    echo "$1: $SYSL_ID"
fi

Скрипт целиком

На PasteBin
На GitHub

Источники

1. Syslinux (Русский)
2. Работа со строками
3. BASH: Получить номер буквы в латинском алфавите, более элегантное решение. Копия

Замечательные опечатки.

В околошкольной крипипасте:

сжечь ему эту погонь

Интересно, кого полагалось сжечь, местного военкома, или даже целого министра обороны?

За «погонью» идет ее сестра «серень», наверное, весьма зловонное растение.

На участке бабушки вовсю цвела серень

И, наконец, финалист нашего сегодняшнего хит-парада, мужыкальный, прям-таки инструмент из теста по музыке — сексофон.

Случай в магазине

Как у поэта Лесина о природе зла/добра.

Стою в магазине я, в очереди на кассу, пробиваю себе вкусный бич-пакет Биг-Бон, нравятся они мне очень.
По передо мной стоит «сердобольная» тетушка, из серии тех проклятых «сердоболов», которые будут поудобнее укладывать человека с переломом основания черепа до приезда скорой, вызывать скорую мирно отдыхающему пьянице, или рассказывать про вред ГМО и прививок, ежили их, наконец, догнало мракобесие в терминальной стадии.

— Вот зачем вы эту гадость покупаете, в этих бич-пакетах одна химия! Купите лучше макарон простых!
— Женщина, милая, вот вы приходите домой, включаете свет. Так вот, в лампочке — физика! Если у вас телефон с компьютером есть — в них математика и ее подруга информатика, а у вас самой внутри — биология. Если дома есть кот, то сразу две биологии в одной квартире! Знаете, жить вообще страшно, куда ни плюнь, везде какая-нибудь наука…

Один из немногих моментов, когда я узрел подтверждение гипотезы, что человек, однако, своего рода компьютер. Я увидел BSOD в реальности. А у кассирши, явный перегруз модуля «корпоративной вежливости».

BASH: Получить номер буквы в латинском алфавите, решение «в лоб».

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

#!/bin/bash
alf="abcdefghijklmnopqrstuvwxyz" #переменная, хранящая паттерн
b=`expr index $alf $1`
echo "$1 is $b"

Чтоб нумерация начиналась с 0, меняем строку
b=`expr index $alf $1`
на
b=`expr index $alf $1 - 1`

Примечание: параметр index команды expr позволяет получить индекс строковой последовательности: index <где_найти> <что_найти>

Готовый скрипт с проверками

На PasteBin
На GitHub

Остальные варианты решения той же задачи.

1. С помощью операторов for и if Копия
2. С помощью printf Копия

BASH: Получить номер буквы в латинском алфавите, более элегантное решение.

В комментариях предложили более элегантное решение этой задачки.

#!/bin/bash

code=`printf '%d' \'$1`
a_code=`printf '%d' \'a`
answer=$( expr $code - $a_code )
echo $answer

Разберем код подробно.

1. printf — команда, выводящая текст (обычно на экран), с учетом заданной форматирующей строки. Подробнее о команде printf можно почитать в источниках, а вообще башевский printf, является аналогом printf из C++, и ее рекомендуют для замены древней команды echo в bash-скриптах.

Первым параметром является строка, описывающая формат, в данном случае '%d' означает, что нужно вывести десятичное число.
Второй параметр — выводимая строка.
Перед вторым параметром добавляется символ ‘ (одна одинарная кавычка): Интерпретируется как кодовый номер этой буквы в текущей кодировке [1], одинарную кавычку экранируем символом \.

Таким образом, в переменной code окажется код первого символа из первого параметра командной строки скрипта.

2. Далее, таким же образом, получаем код первой буквы в алфавите.
3. В итоге, получаем номер буквы в алфавите, посчитав выражение с помощью оператора expr [2]

Примечания

1. Этот код не будет работать на некоторых довольно странных устройствах, где кодовая таблица латинского алфавита представляет собой перемежающиеся заглавные и строчные буквы: AaBbCcDd и т.д. (или aAbBcCdD…)
2. Чтобы отсчет букв шел с единицы, необходимо изменить выражение answer=$( expr $code - $a_code ) на

answer=$( expr $code - $a_code + 1 )
3. С кириллицей этот способ не сработает, используйте предыдущий

По вкусу можно добавить проверки, как в предыдущем скрипте.

Готовый скрипт

На GitHub
На PasteBin

Дополнительно

1. Статья про printf
2. Описание оператора expr

Котопанк Шредингера.

Можно сказать, что номерследующий N-ART за 2019 г.

Джва года ждал этой картинки. Нарисовано вручную, и так, скорее всего, пойдет без изменений на новую футболку #2. Разве что текст добавлю.

Остальные файлы здесь

BASH: Получить номер буквы в латинском алфавите.

Преамбула

Вопрос был задан студенту-первокурснику преподом на зачете по Linux. Студент на вопрос не ответил и вчера ушел на пересдачу, впрочем, задав вопрос мне. Думаю, формулировка задания понятна. Я, кстати, сначала тоже запарился, и начал выдумывать всякие дикие варианты с получением кода символа, преобразованием кода символа в номер буквы латинского алфавита, потом подумал, что иметь секс с локалью (разбирайся еще, юникод не юникод) не стоит, и родил вот такое простое решение с помощью цикла for и оператора if.

Решение

Нужную букву будем брать из параметра командной строки скрипта.

#!/bin/bash

#get number of latin letter in alphabet
#use nlett <letter>, e.g nlett a

SNUM=1

for SYMB in {a..z}; do
    if [[ "$SYMB" == "$1" ]]; then
	break
    else
	let "SNUM=SNUM+1"
    fi
done

echo "$1 is $SNUM"

Перебираем в цикле все буквы от a до z, нашли нужную — выводим номер, не нашли — увеличиваем счетчик $SNUM.
Чтобы отсчет шел с 0, просто присваиваем начальному значению счетчика 0:
SNUM=0

Дополнительная проверка

Чтобы пользователь не ввел ничего лишнего, а только маленькую латинскую букву, можно добавить проверку перед циклом for:

SFND=`echo $1|grep '^[a-z]$'`
if [ -z "$SFND" ]; then
    echo "Error: in first parameter must be one small latin letter!"
    exit 1
fi

И заменить в цикле и далее $1 на $SFND.

Скрипт целиком

На PasteBin
На GitHub

Есть и более элегантное решение.

Получение относительного пути в Linux

Преамбула

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

Пример

Скажем, есть 2 каталога, известны полные пути:
/tmp/test/dir1/subidr1/startpoint и /tmp/test/dir2/subdir2/endpoint, надо получить относительный путь из каталога startpoint в каталог endpoint

Команда realpath.

Проще всего получить относительный путь командой realpath со следующими параметрами:

realpath --relative-to="ОТКУДА" "КУДА"
где:
ОТКУДА — стартовый каталог
КУДА — конечный каталог

Выполнение команды
realpath --relative-to="/tmp/test/dir1/subidr1/startpoint" "/tmp/test/dir2/subdir2/endpoint"
выведет на экран относительный путь:
../../../dir2/subdir2/endpoint

Если каталог не существует, будет отображена ошибка:
realpath: /tmp/test/dir2/subdir2/endpoint: No such file or directory

Утилита realpath входит в пакет coreutils, поэтому есть везде, кроме старых и совсем урезанных дистрибутивов:

Тестовый скрипт

#!/bin/bash

#get relative path example
#start path: /tmp/test/dir1/subidr1/startpoint
#end path: /tmp/test/dir2/subdir2/endpoint

START="/tmp/test/dir1/subidr1/startpoint"
END="/tmp/test/dir2/subdir2/endpoint"

mkdir -p "$START"
mkdir -p "$END"

cd "$START"
echo -n "Start directory:"
pwd

RP=`realpath --relative-to="$START" "$END"`
echo "Relative path: $RP"

echo "CD to relative path:"
cd "$RP"

echo -n "End directory:"
pwd

На PasteBin
На GitHub

Источник

qaru.site — там предлагаются и другие способы, разной степени велосипедности, например, использовать Python или получать относительный путь исключительно средствами оболочки (на мой взгляд, неудобно, и можно где-нибудь накосячить).

САТАНИНСКИЕ ГЛУБИНЫ

Навели тут на автобиографическую книгу какого-то известного ранее ЖеЖиста, охрененная штука оказалась, дико контркультурная, почти что Баян Ширянов, и собственно да, вещества и секс в книге присутствуют в полном объеме. Говорят, автор жив до сих пор, не торчит, у него жена, дети и бизнес.

Книга была в виде сайта на «Народе», но проклятые хуяндексовские цензоры ее снесли. Благо добрые люди дали ссылку на Вебархив.

Однако, у автора местами вырвиглазные фоны, прям-таки вениаминные, так что я собрал все это дело в ПДФ-ку, чтоб читать было удобнЕй!

Правда без содержания и навигации, но мне просто лень. Если кто-нибудь сделает, буду рад. А вообще, кто связывался с Флибустой — лучше сделать FB2, и залить туда.

Скачать бесплатно без СМС с Mega.nz

Как добавить картинку в readme на GitHub

Очередная заметка «от склероза». Товарищ [info]is3@ljr посоветовал добавить скриншоты в readme проекта ASCII-капчи, а я ж, как обычно, мануалы читаю в последнюю очередь, и даже не знал о такой возможности. А она есть.

1. Грузим картинки на GitHub, желательно в отдельный каталог, например screnshoots. Лучше грузить скрины в сам репозиторий, хотя GitHub позволяет вставку картинок и с других сайтов.

2. Добавляем следующий код в README.md:

![Описание](http(s)://адрес_картинки.png(jpg))

3. Пример:

# Screenshoots

ASCII captcha:

![ASCII captcha](https://raw.githubusercontent.com/tolik-punkoff/ascii-captcha/master/screnshoots/test01.png)

ASCII captcha on real HTML page:

![ASCII captcha on real HTML page](https://raw.githubusercontent.com/tolik-punkoff/ascii-captcha/master/screnshoots/on_page1.png)

User send wrong code:

![User send wrong code](https://raw.githubusercontent.com/tolik-punkoff/ascii-captcha/master/screnshoots/on_page2_wrong%20code.png)

Правда описание у меня нигде не всплыло, но наверное потому, что я использовал браузер в параноидальном режиме, без js.

Простой интерактив в bash-скриптах, часть 2. Списки (меню).

Преамбула

В bash-скрипте можно организовать простое меню, в виде списка, и предоставить пользователю выбор из нескольких вариантов.
Список вариантов можно сформировать вручную, просто перечислив нужные в скрипте. Другой способ — сформировать список динамически, так, как это, например, описано здесь копия. Покажу второй способ.

Сначала возьмем из скрипта по ссылке выше функцию create_list() и необходимые переменные:

FOUNDLST=""
DIR1="/home/smallwolfie/test/archives"
TARGZ=""

create_list() #$1 - dir, $2 - file mask
{
    FOUNDLST=""
    for FLE in $(find $1 -maxdepth 1 -iname $2); do
	if [ -n "$FLE" ]; then
	    FOUNDLST="$FOUNDLST"`basename $FLE`"\n"
	fi
    done
}
#тут будет функция вывода списка
#...
#создаем список
create_list $DIR1 "*.tar.gz"

if [ -z "$FOUNDLST" ]; then
    echo "$DIR1 *.tar.gz not found"
    exit
else
    TARGZ="$FOUNDLST"
fi

Простой вариант с помощью оператора select.

Организуем это дело в виде отдельной функции ask_list(), куда первым параметром передается список, а вторым — запрос для пользователя.

1. Скопируем содержимое первого параметра в переменную $LIST_BUF, со списком придется сделать несколько преобразований:

LIST_BUF=$1

2. Список у меня в виде строк, разделенных стандартным переносом \n, так что заодно добавлю пункт Cancel, чтобы пользователь мог отказаться от выбора.

LIST_BUF="$LIST_BUF""Cancel"

3. Оператор select работает со списком значений, разделенных пробелами, так что надо символы \n заменить на пробелы:

LIST_BUF=`echo -e "$LIST_BUF"|sed 's/\n/ /'`

4. Устанавливаем подсказку ввода для пользователя, присвоив второй параметр функции специальной переменной PS3.

PS3=$2

5. Теперь используем оператор select:

echo
    select LIST_RET in $LIST_BUF; do
	if [ -n "$LIST_RET" ];then
	    break
	fi
    done

На экран будет выведен список, а пользователю будет предложено ввести номер из списка:

smallwolfie@wolfschanze: ~/test/$ ./asklist2

1) slinstall.tar.gz 3) teSt.Tar.gZ 5) Cancel
2) slmini.tar.gz 4) TEST.TAR.GZ
Select file:

Если внутри конструкции select..done не поставить break, то цикл выбора окажется бесконечным.
Значение (строка после номера) будет записано в переменную, указанную после ключевого слова select.
Если пользователь введет номер не из списка, или вообще что-то левое, то переменная $LIST_RET окажется пустой.
Здесь внутри конструкции select..done добавлена конструкция для проверки этого. Если переменная окажется пустой — пользователю будет предложено повторить ввод:

smallwolfie@wolfschanze: ~/test/$ ./asklist-select

1) slinstall.tar.gz 3) teSt.Tar.gZ 5) Cancel
2) slmini.tar.gz 4) TEST.TAR.GZ
Select file: blablabla
Select file:

Функция целиком:

ask_list() #$1 - list #$2 - header
{
    LIST_BUF=$1
    LIST_BUF="$LIST_BUF""Cancel"
    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
    
}

Пример вызова функции:

ask_list "$TARGZ" "Select file: "

if [[ "$LIST_RET" == "Cancel" ]]; then
    echo "Cancelled by user!"
    exit
fi

echo "User select: $LIST_RET"

Результат:

smallwolfie@wolfschanze: ~/test/$ ./asklist-select

1) slinstall.tar.gz 3) teSt.Tar.gZ 5) Cancel
2) slmini.tar.gz 4) TEST.TAR.GZ
Select file: 5
Cancelled by user!

smallwolfie@wolfschanze: ~/test/$ ./asklist-select

1) slinstall.tar.gz 3) teSt.Tar.gZ 5) Cancel
2) slmini.tar.gz 4) TEST.TAR.GZ
Select file: 3
User select: teSt.Tar.gZ

Скрипт на GitHub
Скрипт на PasteBin

Второй вариант, быдлокодерский, с жирным башизмом, более длинный, но красивее смотрится на экране.

Под катом

Источники

Взаимодействие bash-скриптов с пользователем. Часть 2