Как убедить tar (и т.д.). заархивировать содержание блочного устройства?

К сожалению, в странице справочника говорится это sort <no options> | join <no options> не работает:

   Important: FILE1 and FILE2 must be sorted on the join fields.  E.g.,
   use ` sort -k 1b,1 ' if `join' has no options, or use ` join -t '' ' if
   `sort' has no options.

Таким образом, Вы могли попробовать:

sort flash_int_list.txt | join -t '' finish_comm - > t1

или:

sort -k 1b,1 flash_int_list.txt | join finish_comm - > t1
13
10.05.2015, 11:03
3 ответа

Недавно я хотел сделать это с помощью tar . Некоторое расследование показало мне, что то, что я не мог, было более чем бессмысленным. Я придумал эту странную split --filter = "cat> file; tar -r ..." штуку, но она была ужасно медленной. И чем больше я читал о tar , тем более бессмысленным он казался.

Видите ли, tar - это просто составной список записей. Составляющие файлы никоим образом не изменяются - они целиком внутри архива. Но они заблокированы на границах 512-байтового блока , и перед каждым файлом стоит заголовок . Вот и все. Формат заголовка действительно очень прост.

Итак, я написал свой собственный tar . Я называю это ... шитар .

z() (IFS=0; printf '%.s\\0' $(printf "%.$(($1-${#2}))d"))
chk() (IFS=${IFS#??}; set -f; set -- $(     
        printf "$(fmt)" "$n" "$@" '' "$un" "$gn"               
);  IFS=; a="$*"; printf %06o "$(($(
        while printf %d+ "'${a:?}"; do a=${a#?}; done 2>/dev/null
)0))")                                                                 
fmt() { printf '%s\\'"${1:-n}" %s "${1:+$(z 99 "$n")}%07d" \
    %07o %07o %011o %011o "%-${1:-7}s" ' 0' "${1:+$(z 99)}ustar  " %s \
    "${1:+$(z 31 "$un")}%s"
}

Это действительно мясо с картошкой. Он записывает заголовки и вычисляет chksum - что, условно говоря, является единственной сложной частью. Он выполняет формат заголовка ustar ... возможно . По крайней мере, он имитирует то, что GNU tar , похоже, считает форматом заголовка ustar , до такой степени, что не жалуется. И это еще не все, просто я еще не коагулировал его. Здесь я покажу вам:

for f in 1 2; do echo hey > file$f; done
{ tar -cf - file[123]; echo .; } | tr \\0 \\n | grep -b .

0:file1                      #filename - first 100 bytes
100:0000644                  #octal mode - next 8
108:0001750                  #octal uid,
116:0001750                  #gid - next 16
124:00000000004              #octal filesize - next 12
136:12401536267              #octal epoch mod time - next 12
148:012235                   #chksum - more on this
155: 0                       #file type - gnu is weird here - so is shitar
257:ustar                    #magic string - header type
265:mikeserv                 #owner
297:mikeserv                 #group - link name... others shitar doesnt do
512:hey                      #512-bytes - start of file   
1024:file2                   #512 more - start of header 2
1124:0000644
1132:0001750
1140:0001750
1148:00000000004
1160:12401536267
1172:012236
1179: 0
1281:ustar  
1289:mikeserv
1321:mikeserv
1536:hey
10240:.                     #default blocking factor 20 * 512

Это tar . Все дополнено \ 0 нулями, поэтому я просто превращаю em в \ n ewlines для удобства чтения. И ситар :

#the rest, kind of, calls z(), fmt(), chk() + gets $mdata and blocks w/ dd
for n in file[123]
do d=$n; un=$USER; gn=$(id --group --name)
   set -- $(stat --printf "%a\n%u\n%g\n%s\n%Y" "$n")
   printf "$(fmt 0)" "$n" "$@" "$(chk "$@")" "$un" "$gn"
   printf "$(z $((512-298)) "$gn")"; cat "$d"  
   printf "$(x=$(($4%512));z $(($4>512?($x>0?$x:512):512-$4)))"
done |
{ dd iflag=fullblock conv=sync bs=10240 2>/dev/null; echo .; } |
tr \\0 \\n | grep -b .

ВЫХОД

0:file1                 #it's the same. I shortened it.
100:0000644             #but the whole first file is here
108:0001750
116:0001750
124:00000000004
136:12401536267
148:012235              #including its checksum
155: 0
257:ustar  
265:mikeserv
297:mikeserv
512:hey
1024:file2
...
1172:012236             #and file2s checksum
...
1536:hey
10240:.

Я говорю вроде там, потому что это не ситар цель - tar уже делает это красиво. Я просто хотел показать, как это работает - а это значит, что мне нужно коснуться chksum . Если бы не это, я бы просто удалил dd заголовок файла tar и покончил с этим. Иногда это может даже сработать, но когда в архиве несколько участников, это становится беспорядочным. Тем не менее, chksum действительно прост.

Во-первых, сделайте это 7 пробелов - (я думаю, что это странная вещь GNU, поскольку в спецификации указано 8, но что бы то ни было - хак - это хак) . Затем сложите восьмеричные значения каждого байта в заголовке. Это твой чксум. Таким образом, вам нужны метаданные файла до того, как вы создадите заголовок, иначе у вас нет chksum. И это в основном архив устар .

Хорошо. Теперь, что он предназначен для выполнения:

cd /tmp; mkdir -p mnt     
for d in 1 2 3                                                
do  fallocate -l $((1024*1024*500)) disk$d
    lp=$(sudo losetup -f --show disk$d)
    sync
    sudo mkfs.vfat -n disk$d "$lp"
    sudo mount  "$lp" mnt
    echo disk$d file$d | sudo tee mnt/file$d
    sudo umount mnt
    sudo losetup -d "$lp"
done

Это создает три образа дисков по 500 Мбайт, форматирует и монтирует каждый и записывает файл в каждый.

for n in disk[123]
do d=$(sudo losetup -f --show "$n")
   un=$USER; gn=$(id --group --name)
   set -- $(stat --printf "%a\n%u\n%g\n$(lsblk -bno SIZE "$d")\n%Y" "$n")
   printf "$(fmt 0)" "$n" "$@" "$(chk "$@")" "$un" "$gn"
   printf "$(z $((512-298)) "$gn")"
   sudo cat "$d"
   sudo losetup -d "$d"
done | 
dd iflag=fullblock conv=sync bs=10240 2>/dev/null |
xz >disks.tar.xz

Примечание - очевидно, что блочные устройства всегда будут правильно блокироваться. Довольно удобно.

Этот tar является содержимым файлов дискового устройства в потоке и направляет вывод в xz .

ls -l disk*
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk1
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk2
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk3
-rw-r--r-- 1 mikeserv mikeserv    229796 Sep  3 01:05 disks.tar.xz

Теперь момент истины ...

 xz -d <./disks.tar.xz| tar -tvf -
-rw-r--r-- mikeserv/mikeserv 524288000 2014-09-03 01:01 disk1
-rw-r--r-- mikeserv/mikeserv 524288000 2014-09-03 01:01 disk2
-rw-r--r-- mikeserv/mikeserv 524288000 2014-09-03 01:01 disk3

Ура! Извлечение ...

xz -d <./disks.tar.xz| tar -xf - --xform='s/[123]/1&/'  
ls -l disk*
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk1
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk11
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk12
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk13
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk2
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk3
-rw-r--r-- 1 mikeserv mikeserv    229796 Sep  3 01:05 disks.tar.xz

Сравнение ...

cmp disk1 disk11 && echo yay || echo shite
yay

И крепление ...

sudo mount disk13 mnt
cat mnt/*
disk3 file3

Итак, в этом случае shitar работает нормально, я полагаю. Я бы предпочел не вдаваться в подробности, которые он не сделает хорошо. Но, я скажу - по крайней мере, не делайте символы новой строки в именах файлов.

Вы также можете - и, возможно, должны, учитывая предложенные мной альтернативы - это с squashfs . Вы не только получаете единственный архив, созданный из потока - , но и mount способный и встроенный в ядро ​​ vfs :

From псевдо -file.example :

# Copy 10K from the device /dev/sda1 into the file input.  Ordinarily
# Mksquashfs given a device, fifo, or named socket will place that special file
# within the Squashfs filesystem, this allows input from these special
# files to be captured and placed in the Squashfs filesystem.
input f 444 root root dd if=/dev/sda1 bs=1024 count=10

# Creating a block or character device examples

# Create a character device "chr_dev" with major:minor 100:1 and
# a block device "blk_dev" with major:minor 200:200, both with root
# uid/gid and a mode of rw-rw-rw.
chr_dev c 666 root root 100 1
blk_dev b 666 0 0 200 200

Вы также можете использовать btrfs (send | receive) для потоковой передачи вложенного тома в любой компрессор с поддержкой stdin , который вам нравится. Конечно, этот подобтом не должен существовать, прежде чем вы решите использовать его в качестве контейнера сжатия.

Тем не менее, насчет сквошов ...

Я не верю, что делаю это справедливо. Вот очень простой пример:

 cd /tmp; mkdir ./emptydir
 mksquashfs ./emptydir /tmp/tmp.sfs -p \
    'file f 644 mikeserv mikeserv echo "this is the contents of file"'                             

Parallel mksquashfs: Using 6 processors
Creating 4.0 filesystem on /tmp/tmp.sfs, block size 131072.
[==================================================================================|] 1/1 100%
Exportable Squashfs 4.0 filesystem, gzip compressed, data block size 131072
        compressed data, compressed metadata, compressed fragments,... 
###...
###AND SO ON
###...

echo '/tmp/tmp.sfs /tmp/imgmnt squashfs loop,defaults,user 0 0'|
    sudo tee -a /etc/fstab >/dev/null

mount ./tmp.sfs     
cd ./imgmnt
ls

total 1
-rw-r--r-- 1 mikeserv mikeserv 29 Aug 20 11:34 file

cat file

this is the contents of file

cd ..
umount ./imgmnt

Это только встроенный -p аргумент для mksquash . Вы можете создать файл с помощью -pf , содержащий столько файлов, сколько захотите. Формат прост - вы определяете имя / путь к целевому файлу в файловой системе нового архива, вы указываете ему режим и владельца, а затем указываете ему, какой процесс выполнять и откуда читать stdout. Вы можете создавать сколько угодно - и вы можете использовать LZMA, GZIP, LZ4, XZ ... хм, есть еще ... форматы сжатия, какие захотите. И конечный результат - это архив, в который вы cd .

Подробнее о формате:

Это, конечно, не просто архив - это сжатый монтируемый образ файловой системы Linux. Его формат - это ядро ​​Linux - это файловая система, поддерживаемая ванильным ядром. Таким образом, он так же распространен, как и ванильное ядро ​​Linux. Так что, если бы вы сказали мне, что используете обычную систему Linux, на которой не установлена ​​программа tar , я бы усомнился, но я бы, вероятно, вам поверил.Но если бы вы сказали мне, что используете обычную систему Linux, в которой файловая система squashfs не поддерживается, я бы вам не поверил.

11
27.01.2020, 19:53

Ваша проблема какое-то время меня озадачивала, и я думаю, что нашел решение, которое сработает.

Я думаю, что вы можете добиться желаемого с 7z, используя флаг -si {NAME} .

Вы сможете адаптироваться к своим потребностям.

7z a test.7z -siSDA2.txt < /dev/sda1
7z a test.7z -siSDA2.txt < /dev/sda2

7z l test.7z 

7-Zip [64] 9.20  Copyright (c) 1999-2010 Igor Pavlov  2010-11-18
p7zip Version 9.20 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,8 CPUs)

Listing archive: test.7z

--
Path = test.7z
Type = 7z
Method = LZMA
Solid = -
Blocks = 2
Physical Size = 1770
Headers Size = 162

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2014-08-19 22:01:08 .....         6314          804  SDA1.txt
2014-08-19 22:01:11 .....         6314          804  SDA2.txt
------------------- ----- ------------ ------------  ------------------------
                                 12628         1608  2 files, 0 folders

ИЗМЕНИТЬ : Убрать бесполезное использование кота

4
27.01.2020, 19:53

Если вам все равно, делает это tar или нет, и все, что вам нужно, это архив содержимого блочного устройства, вы можете использовать ddrescue, который создаст двоичный образ устройства с именем файла по вашему выбору.. Программа установки (для Debian )называется gddrescue.

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

0
15.03.2021, 15:13

Теги

Похожие вопросы