Я пытаюсь получить только последние 1024 байта /dev /sda2. Когда я делаю sudo tail -c 1024 /dev/sda2 | hd
, приглашение просто зависает, пока я не нажму Ctrl-C. Тем не менее, когда я tail -c 1024 ddfilecopyofsda2 | hd
, я сразу получаю хороший вывод из последних 1024 байтов файла. Я прочитал здесь (https://unix.stackexchange.com/questions/60034/what-are-character-special-and-block-special-files-in-a-unix-system), что «блочные устройства обычно доступны для поиска, "так чего мне не хватает?
1 ответ
Вот один из способов получить последние 1024 байта блочного устройства:
last_bytes() { sudo dd if=$2 iflag=skip_bytes skip=$(($(sudo blockdev --getsize64 $2) - $1)) bs=1M ; } ; last_bytes 1024 DEVICE
Замените DEVICE
на путь устройства. В вашем случае вы бы использовали /dev/sda2
.
Теперь на более интересный вопрос, чтобы ответить ...
Почему tail -c 1024 /dev/sda2
ищет весь диск?
Причина в том, как реализован tail
. Когда tail
знает размер файла, который он читает, он точно знает, сколько искать. В противном случае, он должен прочитать файл или поток полностью, чтобы выяснить, как далеко отсчитывать.
С трубами это имеет смысл, как cat /dev/sda2 | tail -c 1024
. tail
получает содержимое в виде потока и не может знать, когда данные закончатся.
Вы можете ожидать, что tail -c 1024 /dev/sda2
сможет определить размер /dev/sda2
, но на самом деле, когда tail
смотрит вверх /dev/sda2
, он открывается как блочное устройство вместо обычного файла.
Детали реализации в том, что tail
вызывает fstat()
для получения информации о файле.
tail
на обычном файле
Вот соответствующая часть strace
примера tail
открытия файла:
21:30:27 open("/var/log/syslog", O_RDONLY) = 3
21:30:27 fstat(3, {st_dev=makedev(0, 22), st_ino=4715, st_mode=S_IFREG|0640, st_nlink=1, st_uid=104, st_gid=4, st_blksize=131072, st_blocks=54, st_size=175500, st_atime=2017/11/10-21:28:39.243133398, st_mtime=2017/11/10-21:30:20.438031639, st_ctime=2017/11/10-21:30:20.438031639}) = 0
21:30:27 lseek(3, 0, SEEK_CUR) = 0
21:30:27 lseek(3, 174476, SEEK_SET) = 174476
fstat()
предоставляет st_size=175500
. Теперь tail
просто должен считать обратно 1024 байта:
175500 - 1024 = 174476
... и это именно то, что делает
tail
:lseek(3, 174476, SEEK_SET) = 174476
tail
на блочном устройстве
fstat()
на этот раз не возвращает размер !:
21:29:43 open("/dev/sda", O_RDONLY) = 3
21:29:43 fstat(3, {st_dev=makedev(0, 6), st_ino=17488, st_mode=S_IFBLK|0660, st_nlink=1, st_uid=0, st_gid=6, st_blksize=4096, st_blocks=0, st_rdev=makedev(8, 0), st_atime=2017/11/10-09:21:15.643998960, st_mtime=2017/11/10-09:21:15.555998962, st_ctime=2017/11/10-09:21:15.555998962}) = 0
Без st_size
tail
не может знать, как далеко искать, поэтому по умолчанию он читает все блочное устройство до конца.
Вот почему вы должны обычно использовать инструменты блочных устройств, такие как dd
для управления блочными устройствами, а не инструменты, предназначенные для обычных файлов, таких как tail
.
Вы можете спросить: «Как blockdev --getsize64
быстро получает размер блочного устройства?"
Вот sudo strace -vvvfts1000 blockdev --getsize64 /dev/sda
:
21:53:15 open("/dev/sda", O_RDONLY) = 3
21:53:15 ioctl(3, BLKGETSIZE64, [512110190592]) = 0
blockdev
предназначен для получения блочного устройства ioctls, а BLKGETSIZE64
получает размер блочного устройства.
Что касается того, почему tail
не выполняет BLKGETSIZE64
, я не знаю. Исходный код показывает:
#define IS_TAILABLE_FILE_TYPE(Mode) \
(S_ISREG (Mode) || S_ISFIFO (Mode) || S_ISSOCK (Mode) || S_ISCHR (Mode))
Из этой строки я знаю только то, что без S_ISBLK()
авторы не имели в виду tail
поддержку блочных устройств.