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
최대값을 명시적으로 지정하지 마세요. 하지만 몇 가지 제한 사항이 있습니다.
- 주어진 값을 저장하는 데 사용되는 데이터 유형은 다음과 같을 것으로 예상됩니다.
size_t
, 이는 읽을 바이트 수의 유형이기 때문입니다.read
기능; read
한도도 정해져있어요SSIZE_MAX
;- 리눅스에서는,
read
최대 2,147,479,552바이트만 전송할 수 있습니다.그래도.
64비트 플랫폼에서는 size_t
길이가 64비트입니다. 또한 부호가 없으므로 2 64dd
– 1 보다 큰 값이 지정되면 실패합니다 .
$ dd if=/dev/zero of=/dev/null bs=18446744073709551616
dd: invalid number: ‘18446744073709551616’
64비트 x86 Linux에서는 입력 제한인 SSIZE_MAX
0x7ffffffffffffffffL(실행하여 확인)입니다 .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에 설명된 대로 fullblock
1보다 큰 값에 대해서는 어떤 경우에도 모든 입력 데이터를 안정적으로 복사해야 합니다.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