파일에서 정확한 바이트 수를 읽는 POSIX 방법은 무엇입니까?

파일에서 정확한 바이트 수를 읽는 POSIX 방법은 무엇입니까?

방금 이 질문에 부딪혔고 선택한 답변에서 많은 것을 배웠습니다.dd를 사용하여 임의의 데이터를 생성하고 "부분 읽기 경고"가 발생합니다. 이제 경고 이후의 데이터는 정말 무작위인가요?

불행하게도 제안된 솔루션 head -c은 이식성이 없습니다.

dd이것이 답변이라고 주장하는 분들은 링크된 답변을 주의 깊게 읽어보시기 바랍니다. 여기에는 왜 dd답변이 될 수 없는지 자세히 설명되어 있습니다. 또한 다음 사항에 유의하세요.

$ dd bs=1000000 count=10 if=/dev/random of=random
dd: warning: partial read (89 bytes); suggest iflag=fullblock
0+10 records in
0+10 records out
143 bytes (143 B) copied, 99.3918 s, 0.0 kB/s
$ ls -l random ; du -kP random
-rw-rw-r-- 1 me me 143 Apr 22 19:19 random
4       random
$ pwd
/tmp

답변1

불행하게도 바이너리 파일의 내용을 조작하는 것은 ddPOSIX에서 사용할 수 있는 거의 유일한 도구입니다. 텍스트 처리 도구( cat, sed, , ...) 의 최신 구현은 awk바이너리 파일에서 작동할 수 있지만 이는 POSIX 요구 사항이 아닙니다. 일부 이전 구현은 널 바이트, 줄 바꿈으로 종료되지 않은 입력 또는 잘못된 바이트로 인해 실패합니다. 환경 문자 블록 인코딩의 시퀀스입니다.

안전한 사용은 가능하지만 어렵습니다 dd. 내가 사람들을 멀리하도록 많은 노력을 기울이는 이유는 dd그것이 쓸모없고 안전하지 않을 때 그것을 홍보하는 많은 조언이 있기 때문입니다 .

문제는 dd블록 개념입니다. 호출을 가정합니다.read청크를 반환합니다. read더 적은 양의 데이터가 반환되면 부분 청크를 얻게 되며, 이는 다음과 같은 것들을 skip버립니다 count. 다음 예에서는 dd데이터를 상대적으로 느리게 전송하는 파이프에서 데이터를 읽는 문제를 보여줍니다.

yes hello | while read line; do echo $line; done | dd ibs=4 count=1000 | wc -c

습지 표준 Linux(Debian jessie, Linux 커널 3.16, ddGNU coreutils 8.23)에서 내가 얻는 바이트 수는 약 3000에서 거의 4000까지 매우 다양합니다. 입력 블록 크기를 제수 6으로 변경하면 순진하게 예상한 대로 출력은 항상 4000바이트입니다. 입력은 dd6바이트의 버스트로 도착하며 블록이 여러 버스트에 걸쳐 있지 않는 한 dd괜찮습니다 . 완전한 블록.

이는 해결책을 제안합니다.입력 블록 크기 1 사용. 입력이 어떻게 생성되든 dd입력 블록 크기가 1이면 부분 블록을 읽을 수 없습니다. (이것은 완전히 명확하지는 않습니다. dd신호에 의해 중단되면 크기 0의 블록을 읽을 수 있습니다. 그러나 신호에 의해 중단되면 read시스템 호출은 -1을 반환합니다. read파일이 열린 경우에만 0을 반환할 수 있습니다. 비 차단 모드에서는 차단 모드에서만 파일 끝에서 0을 반환 한다고 생각하지 않는 것이 좋습니다 read.read

dd ibs=1 count="$number_of_bytes"

이 접근 방식의 문제점은 속도가 느릴 수 있다는 것입니다(그러나 놀랄 만큼 느리지는 않습니다. head -c빠른 벤치마크보다 약 4배 느릴 뿐입니다).

POSIX는 바이너리 데이터를 읽고 이를 텍스트 형식으로 변환하기 위한 추가 도구를 정의합니다.uuencode(기록 uuencode 형식 또는 Base64로 출력),od(8진수 또는 16진수 덤프를 출력합니다). 둘 다 현재 작업에 적합하지 않습니다. uuencode이 작업은 다음으로 취소할 수 있습니다.uudecode, 그러나 출력 라인당 바이트 수가 표준화되지 않았기 때문에 출력의 바이트 수를 계산하는 것이 어색합니다. 에서 잘 정의된 출력을 얻는 것이 가능 od하지만 불행하게도 POSIX 도구는 그 반대 방향으로 수행할 수 없습니다(이 작업은 수행할 수 있지만 sh 또는 awk의 느린 루프를 통해서만 수행할 수 있으므로 여기서 목적을 달성할 수 없습니다).

답변2

최신 버전의 GNU 구현에는 iflag dd가 있습니다 count_bytes. 예를 들어:

cat /dev/zero | dd count=1234 iflag=count_bytes | wc -c

다음과 같이 출력됩니다

2+1 records in
2+1 records out
1234 bytes (1.2 kB, 1.2 KiB) copied, 0.000161684 s, 7.6 MB/s
1234

답변3

사용 목적 중 하나 dd는 사용자가 사용하는 블록 크기를 선택할 수 있다는 것입니다. 블록 크기가 너무 커서 실패 하면 dd더 작은 블록 크기를 시도하는 것은 IMO의 책임입니다. 테라바이트 단위의 블록을 요청할 수 있지만 dd그렇다고 해서 얻을 수 있다는 의미는 아닙니다.

정확한 바이트 수를 원하는 경우 매우 느리지만 작동합니다.

dd bs=1 count=1000000

블록 크기라도 1부분 읽기가 발생하면…

관련 정보