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