dd - convert and copy a file

일단 디스크를 덤프한다고 제목에 쓰긴 했는데, 프로그램이 disk dump는 아니고… dd는 도대체 어디서 나온 단어인가? 하는 이야기가 참 많다. 처음에는 Delete Disk인줄 알았는데, 그 다음에는 Disk Duplicator 뭐 이런걸까? man페이지에서도 딱히 어원이나 의미가 잘 나오지 않아서 대략 위키피디아나 스택오버플로 등의 여러 사이트를 찾아보면

dd는 파일을 복사/변경하는 등의 작업을 하는 프로그램이다. 이 프로그램의 중요한 포인트는 접근해야 하는 데이터가 표준 입력이 아니라 파일이라도 상관없다는 것이다.(실제로는 표준 입/출력을 통해서는 거의 안쓰긴 하는 것 같다.)

$ dd if=/dev/zero of=/swapfile bs=1024 count=1048576

과 같은 식으로 장치 /dev/zero로부터 가져온 데이터를 swapfile 파일에 쓰니까 별로 와닿지 않는데, if, of가 어떤 것이든 리눅스 내에서 파일로 관리된다면 그것을 장치로 사용할 수 있다는 것.

dd는 보통 파일을 새로 만들거나 할 때, 디스크를 백업할 때 사용한다. 회사를 퇴사할 때는 사용하던 컴퓨터의 디스크에 항상 dd를 통해 /dev/urandom을 집어넣고 간다거나, 사용하는 리눅스의 디스크를 교체할 때 dd로 덤프를 뜨고 새 디스크에 dd를 사용해서 복원해 교체하여 사용하거나 하는 용도.. 또 뭔가 디스크를 정기적으로 백업할 때 사용했다. 요 정도만 써도 굉장히 유용하게 사용할 수 있다. 특히 sd카드 여러개에 동일한 컨텐츠를 넣어야 하는 경우, dd를 통해 하나의 골든이미지를 만들고 이걸 여러 sd카드에 다시 넣기만 해도 작업이 굉장히 편리하다.

어쨌든 dd를 통해 if로부터 데이터를 그대로 덤프를 떠서 of에 저장하는데, 얼마나 저장할지 등의 여러 옵션을 파라미터로 전달한다. 이 파라미터는 종류가 꽤 많은데 실제로 사용하는 것은 거의 고정되어 있고 다양한 형태로는 사용하지 않는 것 같아서 간단한 파라미터 몇 개만 정리해 보자.

  • if: 파일로부터 인풋을 받는다. 명시하지 않으면 표준 입력 stdin으로부터 데이터를 받는다.
  • of: 마찬가지로 파일로 아웃풋을 낸다. 명시하지 않으면 stdout에 데이터를 쓴다.
  • bs: BYTES, 한 번에 읽어들일 바이트 사이즈를 지정한다. M이나 k등을 써서 지정할 수 있다. 이를 입/출력에 따라 세분화시킨 파라미터가 각각 ibs, obs가 된다. 따라서 이 설정이 뒤에 따라오면 ibs, obs를 오버라이드한다.
  • count: 몇 번의 input을 처리할 것인가? 정확히는 n개 인풋 블록만을 복사하는 역할. bs와 count의 곱이 dd로 처리할 총 바이트 수가 된다.
  • skip, seek: skip은 입력, seek은 출력에서 bs만큼을 건너뛰고 처리한다. 당연히 각각 ibs, obs가 우선이다. 출력 대상의 앞 부분을 지우고 싶지 않으면 seek을 사용하면 된다.
  • conv: dd의 소개 중 convert를 이 conv를 사용해서 처리한다. 이는 아래에서…
  • iflag/oflag: 플래그를 지정할 수 있는데 이건 그냥 man페이지를 보자.

읽고 쓸 총 데이터의 크기는 bscount로 정해진다. 따라서 같은 사이즈를 읽고 쓰게 되더라도 이 옵션이 다양하게 정해질 수 있다는 뜻이다. 여기에서 조금 더 자세한 내용을 살펴보자.

dd는 위에 인용구대로 convert도 수행하는 프로그램이다. 이는 파라미터 conv에서 선택할 수 있는데 사실 이런 변환은 이제 굳이 dd에서 하지 않아도 될 것 같고 표준 출력으로 보내기만 한다면 다른 툴로도 충분히 처리할 수 있어서… 무엇보다 기본 제공하는 플래그들이 지금은 거의 사용할 일이 없는 것들이 대부분이다.

  • lcase/ucase: 입력을 소문자(lcase), 대문자(ucase)로 변환한다.
  • notrunc: 결과 파일을 잘라내지 않는다. 이게 어떤 케이스인가 하면 of가 100MB인데 if에서 1MB를 주면 dd가 완료된 후 of도 1MB로 변한다. notrunc는 뒤 of의 뒤 99MB도 같이 유지하도록 한다.

iflag/oflag/conv 모두 지금은 잘 쓰이지 않고 앞으로도 잘 쓰이지 않을 것 같다. 대체 가능한 다른 방법이나 프로그램이 많이 있어서… 여태 일 하면서 위 notrunc 이외에는 크게 뭐를 사용해 본 경험도 없는 것 같다.

dd는 작업 진행 상황을 실시간으로 볼 수가 없다. 따라서 여러 방법을 사용하는데 가장 대표적으로는 pv를 사용하여 확인한다. dd를 통해 /dev/urandom을 파이프로 출력하고 pv는 이를 받아 다시 파이프 출력하며 dd가 이걸 받아 /dev/null로 그냥 보내서 없애버린다. 따라서 pv는 중간에 서서 데이터를 받아 전달하며 진행 상황을 체크할 수 있다.

$ dd if=/dev/urandom | pv | dd of=/dev/null
 121MiB 0:00:05 [24.1MiB/s] [     <=>                            ]

다른 하나는 man페이지에도 써 있지만 SIGUSR1 시그널을 받으면 프로그레스를 바로 출력한다.

Sending a USR1 signal to a running ‘dd’ process makes it print I/O statistics to standard error and then resume copying.

$ dd if=/dev/sda of=/dev/null bs=1M 
1871+0 레코드 들어옴
1870+0 레코드 나감
1960837120 bytes (2.0 GB, 1.8 GiB) copied, 8.56011 s, 229 MB/s
2309+0 레코드 들어옴
2308+0 레코드 나감
2420113408 bytes (2.4 GB, 2.3 GiB) copied, 10.5515 s, 229 MB/s
2534+0 레코드 들어옴
2533+0 레코드 나감
2656043008 bytes (2.7 GB, 2.5 GiB) copied, 11.5761 s, 229 MB/s
^C2803+0 레코드 들어옴
2802+0 레코드 나감
2938109952 bytes (2.9 GB, 2.7 GiB) copied, 12.7985 s, 230 MB/s
...

네 번의 SIGUSR1을 보냈더니 위와 같이 진행 상태가 표시된다.

간단한 예제

더 특이한 뭔가가 있다면 한번 여기에 계속 추가하려고 하는데 사실 특별할 것이 없다. 생각나면 더 추가하려고 한다.

swapfile 생성

$ dd if=/dev/zero of=/swapfile bs=1024 count=1048576

부트로더 백업

mbr은 디스크의 첫 섹터를 사용하는데, 따라서 요 첫 바이트만 읽어서 디스크에 백업할 수 있다.

$ dd if=/dev/sda bs=512 count=1 of=mbr.img

대소문자 변환

$ echo "asdf" | dd conv=ucase
ASDF
0+1 레코드 들어옴
0+1 레코드 나감
5 bytes copied, 0.000226541 s, 22.1 kB/s

디스크를 초기화하기

한 번을 덮어 쓰기만 해도 디스크의 복구가 어렵다고 하니 전체를 아무렇게나 덮어 쓰자.

$ dd if=/dev/urandom of=/dev/sda bs=1M