dd의 bs 매개변수의 최대값은 얼마입니까?

dd의 bs 매개변수의 최대값은 얼마입니까?

STDIN에서 지정된 바이트 수를 읽어야 하는 CGI를 작성하고 싶습니다. 내 생각은 다음과 같습니다.

dd bs=$CONTENT_LENGTH count=1

하지만 블록 크기가 RAM 이외의 다른 것에 의해 제한되는지 알고 싶습니다.

$ dd bs=1000000000000
dd: memory exhausted by input buffer of size 1000000000000 bytes (931 GiB)

GNU coreutils의 매뉴얼 페이지에는 제한 사항이 지정되어 있지 않습니다.

답변1

POSIX 사양dd최대값을 명시적으로 지정하지 마세요. 하지만 몇 가지 제한 사항이 있습니다.

64비트 플랫폼에서는 size_t길이가 64비트입니다. 또한 부호가 없으므로 2 64dd – 1 보다 큰 값이 지정되면 실패합니다 .

$ dd if=/dev/zero of=/dev/null bs=18446744073709551616
dd: invalid number: ‘18446744073709551616’

64비트 x86 Linux에서는 입력 제한인 SSIZE_MAX0x7ffffffffffffffffL(실행하여 확인)입니다 .echo SSIZE_MAX | gcc -include limits.h -E -

$ dd if=/dev/zero of=/dev/null bs=9223372036854775808
dd: invalid number: ‘9223372036854775808’: Value too large for defined data type

$ dd if=/dev/zero of=/dev/null bs=9223372036854775807
dd: memory exhausted by input buffer of size 9223372036854775807 bytes (8.0 EiB)

허용 가능한 값을 찾으면 다음 제한은 할당할 수 있는 메모리 양입니다. dd버퍼를 읽어오기 전에 버퍼를 할당해야 하기 때문입니다.

할당할 수 있는 값을 찾으면 read한계에 도달하게 됩니다(Linux 및 유사한 한계가 있는 기타 시스템의 경우).GNU를 사용 dd하고 지정 하지 않는 한iflag=fullblock:

$ dd if=/dev/zero of=ddtest bs=4294967296 count=1
0+1 records in
0+1 records out
2147479552 bytes (2.1 GB, 2.0 GiB) copied, 38.3037 s, 56.1 MB/s

( 231dd 바이트 미만 복사됨 ,위에서 언급한 Linux 제한 사항은 내가 요구하는 것의 절반도 되지 않습니다.

위에 링크된 Q&A에 설명된 대로 fullblock1보다 큰 값에 대해서는 어떤 경우에도 모든 입력 데이터를 안정적으로 복사해야 합니다.bs

답변2

최대값이 무엇이든 POSIX 사양에는 더 큰 문제가 있습니다.

dd유틸리티는 가능한 변환을 위해 지정된 입력 및 출력 블록 크기를 사용하여 지정된 입력 파일을 지정된 출력 파일로 복사해야 합니다. 지정된 입력 청크 크기를 사용하여 한 번에 하나씩 입력 청크를 읽어야 합니다. 그런 다음 실제 반환된 데이터 청크를 처리해야 합니다.요청한 블록 크기보다 작을 수 있습니다.

(강조 추가)

제가 예전에 썼던 것처럼dd매우 어리석은 도구입니다. 귀하의 경우에는 본질적으로 다음과 같이 요약됩니다.

char *buf = malloc(bs);
for(int i = 0; i < count; ++i) {
    int len = read(STDIN_FILENO, buf, bs);
    if(len == 0) break;
    write(STDOUT_FILENO, buf, len);
}
free(buf);

bs시스템 호출을 dd수행하는 데 사용되는 인수일 뿐이지만 "짧은 읽기" 수행을 허용합니다. 즉, 요청한 것보다 적은 바이트를 반환합니다. 실제로 요청한 전부가 아니더라도 현재 사용할 수 있는 바이트가 있으면 이 작업을 수행합니다. 이는 입력 파일이 tty, 파이프 또는 소켓인 경우(따라서 특히 CGI가 위험할 경우) 일반적인 경우입니다. ..). 당신은 시도:read(2)read(2)

$ dd bs=1000 count=1
asd
asd
0+1 records in
0+1 records out
4 bytes copied, 1.75356 s, 0.0 kB/s

여기에 입력 asd하고 Enter 키를 누릅니다. dd읽습니다(한 번 수행 read(STDIN_FILENO, buf, 1000)하고 작성합니다. read요청한 대로 한 번 수행하므로 종료됩니다. 1000바이트를 복사한 것처럼 보이지 않습니다.

궁극적으로 단순한 "표준"은 대부분의 요구 사항을 충족하기에는 dd너무 어리석은 도구입니다 . 다음 방법 중 하나로 필요한 작업을 수행하도록 할 수 있습니다.

  • 바이트 수를 사용하면 bs=1필요한 count바이트 수의 복사본이 보장되지만(EOF 이전에 사용 가능한 경우) 바이트당 하나의 시스템 호출을 수행하므로 비효율적입니다.
  • 플래그가 추가되었습니다 fullblock. 이를 통해 dd쓰기 전에 전체 입력 블록이 누적됩니다. 그러나 이것은 비표준입니다(GNU dd에는 있고 다른 것에는 IDK가 있습니다).

궁극적으로 POSIX가 아닌 확장을 사용하려는 경우 그냥 사용하라는 조언이 있습니다 head -c. 합리적인 버퍼링으로 올바른 작업을 수행하고 특정 크기 제한이 없어 정확성과 우수한 성능을 보장합니다.

답변3

최대값은 시스템(할당 정책 포함)과 현재 사용 가능한 메모리에 따라 다릅니다.

당신은 그것을 사용할 수 있습니다 dd.

이 바이트를 읽고 파일에 저장하려고 한다고 가정해 보겠습니다. Bash에서는 다음과 같이 실행할 수 있습니다($total의 총 바이트).

block=65535
count=$(expr $total / $block)
rest=$(expr $total % $block)
(dd bs=$block count=$count;dd bs=$rest count=1) > filename

관련 정보