Нижеследующий вариант неудачный и кривой, благодарю за подсказку хорошего анонима.
Вот нормальный вариант.
Копия на LJR
Вот нормальный вариант.
Копия на LJR
Понадобилось определить файловую систему не смонтированного раздела из ОС. Причем желательно так, чтобы способ работал в нескольких разных дистрибутивах.
Кратко пройдусь по способам, описанным в [1]
1. Команда df
: не подошла, не смонтированные разделы не видит
2. Использование команды mount
и просмотр файла /etc/fstab
, та же беда, что логично.
3. Использование команды fsck
. Способ довольно сомнительный, и команда может не везде быть.
4. Наиболее годным оказался способ с использованием команды file
. Во всяком случае, для линуксовых ФС она почти всегда выдавала то, что нужно, а когда выдавала не совсем то, это можно было немного подправить вручную, но об этом далее. А вот с виндовыми разделами выходила ерунда, и анализировать вывод было неудобно, и почему-то путались разделы FAT/FAT32.
Для экспериментов сделал такую структуру диска, с несколькими ФС, как Linux, так и DOS/Windows:
Далее кратко опишу скрипт detectfs
, запускаемый с единственным параметром — нужное устройство, например, detectfs /dev/sda1
В Линукс есть консольный менеджер разделов диска fdisk
, если запустить его с опцией -l
, то он выведет список всех разделов для всех дисков компьютера.
В выводе fdisk
-l
для моей цели интересна колонка Id, в которой указывается тип раздела, который не следует путать с типом файловой системы на разделе. Но все-таки они коррелируют, на разделе типа 0x7
(NTFS/HPFS) будет файловая система NTFS (или файловая система HPFS, используемая OS/2, впрочем она сейчас встречается очень редко), на разделе 0xf
— FAT32, а на разделе 0x6
— FAT16. На разделе типа 0x83
может присутствовать любая файловая система Linux (EXT2, EXT3, EXT4, BTRFS). Полный список идентификаторов типов разделов можно посмотреть в источнике [2]
Полную справку по fdisk
можно посмотреть с помощью man fdisk
или в [3]
Для этой цели можно применить grep
и awk
.
Минус fdisk
в том, что в зависимости от версии, колонка Id, может со своего места «уплыть»:
Разделители между колонками — пробелы, потому задать нужный номер для awk
«с конца» тоже не получится, идущие подряд пробелы awk
воспримет, как один, так что в этом проблемы не будет. Но номер колонки придется вычислять. Как это делать, я описывал буквально в прошлом посту [4], так что не буду подробно останавливаться на этом, сразу приведу команду, записывающую номер колонки в переменную FLD
.
FSTYPE="" #заодно заведем переменную для хранения типа ФС
FLD=`fdisk -l|grep -w "Id"|head -n1|sed 's/ /\n/g'|nl|grep -w "Id"|awk '{print $1}'`
Далее необходимо обратить внимание на колонку Boot — если раздел активный, там будет стоять *
, а если нет, то она окажется пустой, и awk
, когда будет извлекать данные о разделе, ее проигнорирует. Так что номер колонки надо уменьшить на 1:
let "FLD=FLD-1"
Внимание! Если дисков несколько, для каждого будет выведена своя таблица, соответственно строк со словом Id будет несколько. Чтобы на этапе вычисления не произошло ошибки, надо оставить только первую. Это делает команда head -n1
.
А с символом *
разберемся, когда будем получать информацию о нужном разделе:
1. Выведем информацию обо всех разделах всех дисков:
fdisk -l
2. Отфильтруем grep
‘ом только строку с устройством, заданном в первом параметре скрипта ($1
):
grep -w "$1"
3. Избавляемся от символа *
, заменяя его на пробел:
sed 's/*/ /g'
4. Передаем awk
переменную с номером колонки из bash-скрипта, и вытаскиваем нужный Id:
awk -v fld="${FLD}" '{print $fld}'`
5. Команда целиком:
VOLID=`fdisk -l|grep -w $1|sed 's/*/ /g'|awk -v fld="${FLD}" '{print $fld}'`
Понятно, что скрипт на полную универсальность не претендует, так что анализа всех возможных id тут не будет, но наиболее часто встречающиеся определяем с помощью case
[5]:
#Сначала проверим, есть ли устройство вообще if [ -z $VOLID ];then echo "$1 NO DEVICE" exit 2 fi
case $VOLID in 6) FSTYPE="FAT16" ;; 7) FSTYPE="NTFS" ;; b) FSTYPE="FAT32" ;; f) FSTYPE="EXTENDED" ;; 82) FSTYPE="SWAP" ;; 83) FSTYPE="LINUX" ;; 85) FSTYPE="LINUX EXTENDED" ;; *) FSTYPE="OTHER" ;; esac
Если тип раздела — LINUX, то надо попытаться определить линуксовую FS:
if [[ "$FSTYPE" == "LINUX" ]]; then linux_fs $1 fi
Функция скрипта linux_fs
попытается определить конкретную FS на Linux-разделе и сохранит результат в переменную FSTYPE
.
Выводим результат:
echo "$1 $FSTYPE"
Определял только те, которые мне были нужны: EXT2, EXT3, EXT4 и BTRFS.
Вызов команды file
:
file -sL <filename>
где
-L
— указание программе, что если ей указана символическая ссылка, то надо работать с файлом, на который указывает ссылка.
-s
— указание, что файл является специальным файлом (в нашем случае — файлом блочного устройства [6])
<filename>
— имя файла.
Но оказалось, что и в использовании file
есть подводный камень, в одном из дистрибутивов она не смогла определить BTRFS, и определила EXT4 как EXT3 с пометкой (large files)
.
Все нормально:
Баг с BTRFS и EXT4:
EXT2, EXT4 и BTRFS сделал следующим образом:
1. Функция записывает в переменную результат работы команды file
:
LINUXDATA=`file -sL $1`
2. Выводит результат на консоль, передает его grep
, grep
подсчитывает количество найденных строк с помощью ключа -с
, результат записывается в переменную.
CTR=`echo "$LINUXDATA"|grep -w -c "ext2"`
3. Далее проверяется количество строк. Если их 0, значит проверяется другая FS аналогичным образом, если строка есть — нашли нужную FS. Переменная FSTYPE
соответственно обновляется, и происходит возврат из функции в основной скрипт (return
):
CTR=`echo "$LINUXDATA"|grep -w -c "ext2"` if [ $CTR -ne 0 ]; then FSTYPE="EXT2" return fi
С неверным определением BTRFS решил не бороться, а для EXT3/EXT4 сделал дополнительную проверку. Если файловая система EXT3 (EXT4 проверяется раньше), делаю дополнительный grep
, и проверку наличие фразы «large files
«:
CTR=`echo "$LINUXDATA"|grep -w -c "ext3"` if [ $CTR -ne 0 ]; then CTR=`echo "$LINUXDATA"|grep -c "large files"` #for EXT4 not full support if [ $CTR -ne 0 ]; then FSTYPE="EXT4" else FSTYPE="EXT3" fi return fi
Если до конца функции нигде не вышли return
‘ом, указываем, что файловая система Linux, но какая не определена:
FSTYPE="UNKNOW LINUX FS"
— На мой взгляд, функция определения линуксовых FS кажется достаточно топорной.
— Скрипт криво работает с разделами, которые добавляет kpartx
, например, разделы виртуального жесткого диска, висящего на loop-устройстве, но мне это пока не надо.
1. Как определить тип файловой системы в Linux? Копия
2. List of partition identifiers for PCs Копия
3. fdisk
4. Определение номера колонки таблицы по содержимому (заголовку), для вывода ее awk Копия
5. Краткая справка по оператору case
6. Блочное устройство