Преамбула
Меня спрашивают, а где на практике можно применить «номер буквы в алфавите», про получение которого в 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: Получить номер буквы в латинском алфавите, более элегантное решение. Копия