디스크가 가득 찰 때까지`tar`를`dd`로 파이핑하는 이유는 무엇입니까?


18

단일 디스크 이미지의 tar 아카이브가 있습니다. 이 tar 파일의 이미지 크기는 약 4GB입니다. I 파이프의 출력 tar xfddSD 카드에 디스크 이미지를 작성한다. 카드가 가득 찰 때까지 디스크 덤프는 중지되지 않습니다. 내 셸 세션은 다음과 같습니다.

$ ls -l disk.img.tgz
-rw-r--r-- 1 confus confus 192M Okt  5 00:53

$ tar -tvf disk.img.tgz
-rw-r--r-- root/root 4294968320 2018-10-05 00:52 disk.img

$ lsblk -lb /dev/sdc
NAME MAJ:MIN RM        SIZE RO TYPE MOUNTPOINT
sdc    8:32   1 16022241280  0 disk

$ tar zxf disk.img.tgz -O | sudo dd status=progress conv=sync bs=1M of=/dev/sdc
[sudo] password for user: 
15992881152 bytes (16 GB, 15 GiB) copied, 212 s, 75,4 MB/s 
dd: error writing '/dev/sdc': No space left on device
0+15281 records in
15280+0 records out
16022241280 bytes (16 GB, 15 GiB) copied, 217,67 s, 73,6 MB/s

왜? 히트가 4GB 이미지를 16GB 카트에 쓴 후에는 중지되고 공간이 부족하지 않습니다!


이것을 실행 dd하고 다른 파일에 쓰려고 시도 할 디스크 공간이 있습니까? tar zxf disk.img.tgz -O | dd status=progress conv=sync bs=1M of=/path/to/some/file/on/disk? 그렇다면 원본 파일의 정확한 사본을 얻을 수 있습니까?
Andy Dalton

2
conv=sync있니? conv=fsync아마도 사용하려고 했습니까 ?
Ralph Rönnquist

파일의 실제 크기가 확실합니까? gzip은 파일 크기를 저장할 32 비트 만 가지고 있으므로 4GB 이상의 파일 크기를 잘못 얻습니다. tar가 비슷한 제한을 가지고 있는지 확실하지 않습니다.
David Conrad

답변:


50

당신이 잘못하고 있기 때문입니다.

사용하고 bs=1M있지만 stdin 파이프에서 읽는 것은 더 작은 읽기를 갖습니다. 실제로, dd에 따르면, 당신은 하나의 전체 읽기를 얻지 못했습니다.

그런 다음 conv=sync불완전한 읽기를 0으로 보완하는 것이 있습니다 .

0+15281 records in
15280+0 records out

dd0 전체 및 15281 불완전한 읽기를 수신하고 15280 전체 블록을 썼습니다 (conv = sync zero filled). 따라서 공간이 남지 않을 때까지 출력이 입력보다 훨씬 큽니다.

   sync   pad  every  input  block  with  NULs to ibs-size; when used with
          block or unblock, pad with spaces rather than NULs

이를 해결하기 위해을 제거 conv=sync하고 추가 할 수 있습니다 iflag=fullblock.


예를 들어, yes기본적으로 무한 "y \ ny \ ny \ n"을 분출하는을 고려하십시오 .

$ yes
y
y
y
^C
$ yes | hexdump -C
00000000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
*

으로 dd bs=1M conv=sync는 다음과 같습니다 :

$ yes | dd bs=1M conv=sync | hexdump -C
00000000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
*
0001e000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00100000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
*
00112000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*

따라서 "y \ ny \ ny \ n"(0x00000-0x1e000, 122880 바이트)의 불완전한 블록을 얻은 다음 나머지 1M을 0 (0x01e000-0x100000, 925696 바이트)으로 씁니다. 대부분의 경우, 이런 일이 일어나기를 원하지 않습니다. 결과가 불완전 할 때마다 실제 제어권이 없으므로 결과는 임의적입니다. 여기에서와 같이 두 번째 읽기는 더 이상 122880 바이트가 아니라 73728 바이트입니다.

dd conv=sync거의 유용하지 않으며 읽기 오류가 발생했을 때 0을 쓰는 것과 같이 환영받을만한 경우에도 문제가 심각하게 잘못됩니다.


이 경우 (리눅스 가정) 에서 dd명령을 실행 strace하면 파이프에서 읽은 각 짧은 읽기 다음에 전체 1MB 쓰기가 수행 된 것으로 나타났습니다.
Andrew Henle

2
@AndrewHenle은 이것을 위해 strace가 필요하지 않습니다. 출력을 보는 것만으로도 가능합니다. 그림 추가
frostschutz

이것은 또한 dd명령이 근본적으로 깨지고 사용할 수없는 이유를 보여줍니다 . 개별 reads 및 writes에서 작동하도록 지정되었지만 이러한 작업은 항상 짧은 읽기 또는 쓰기를 생성 할 수 있도록 지정되며 오류가 아닙니다. 결과적으로 동작은 dd지정되지 않은 동작 에 따라 다릅니다.
R ..

매우 교육적인 답변에 감사드립니다. 다른 사람이 제안한 것처럼 나는 엉덩이가되어 많은 옵션을 혼합 dd했지만, 나는 당신에게서 무언가를 배우게합니다. 내가 아직도 확실하지 않은 것은 언제 그리고 언제 끝났는지 dd입니다. 나는 그것을 가지고 있다고 가정하지만 실제로는 1 부분의 실제 데이터와 9 부분의 0을 기록했기 때문에 약 40G를 쓴 후에 중단되었을 것입니다. 그 맞습니까?
con-f-use

@R ..,이 기능은 읽기 및 쓰기의 블록 크기를 관리하는 장치 드라이버에서 매우 유용합니다. 걱정되는 테이프 드라이브를 사용했던 것을 기억합니다. 이 경우에는 반드시 필요한 것은 아니지만 디스크로 직접 리디렉션 할 수 있습니다 (실시간 진행 보고서는 표시되지 않음)
ilkkachu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.