나는 read buildin 명령을 사용하여 읽을 때 bash가 입력 시 이진 0을 무시한다는 것을 발견했습니다. 이 문제를 해결할 방법이 있나요?
작업은 한 번에 12바이트 바이너리 블록, 즉 16비트 정수 2개와 32비트 정수 2개를 전송하는 파이프에서 데이터를 읽는 것입니다. 데이터 속도는 낮으며 성능에는 문제가 없습니다. bash 변수는 C 스타일이기 때문에 분명히 read -N 12 struct
효과가 없으며 NUL 이상의 바이트에는 액세스할 수 없습니다. 그래서 바이트 단위로 데이터를 읽어야 할 것 같습니다 read -N 1 byte
. 해결하기 쉬운 문제는 이스케이프(필수 -r
) 및 UTF 멀티바이트 문자 인코딩( export LC_ALL=C
)입니다. 지금까지 해결할 수 없는 문제는 0바이트를 처리하는 것입니다. 나는 그들이 빈 변수로 나타날 것이라고 생각했지만 byte
실제로 read -r -N 1 byte
0에서는 전혀 반환하지 않고(0을 무시하고) 대신 데이터 스트림에서 0이 아닌 다음 바이트를 반환합니다.
이것이 제가 하려는 작업이며 0이 입력되지 않는 한 완벽하게 작동합니다.
export LC_ALL=C
while true;
do
for ((index = 0; index < 12; index++))
do
read -r -N 1 byte
if [ -n "${byte}" ]; then
struct[${index}]=$(echo -n "${byte}" | od -An -td1)
else
struct[${index}]=0
fi
done
... # some arithmetics reconstructing the four bitfields and processing them
done < pipe
else
의 분기는 결코 사용되지 않는 것으로 나타났습니다 if
. 0을 포함하는 12바이트 데이터 블록으로 인해 루프가 for
12번 실행되지는 않지만 대신 더 많은 데이터가 배열을 채울 때까지 기다립니다 struct
. 다음 명령을 사용하여 파이프에 12바이트를 공급하여 이 동작을 보여줍니다.
echo -en "ABCDE\tGH\0JKL" > pipe
자신을 속이기 쉽기 때문에 0을 보내는 것을 확인했습니다.
~# mkfifo pipe
~# od -An -td1 <pipe &
[1] 25512
~# echo -en "ABCDE\tGH\0JKL" > pipe
~# 65 66 67 68 69 9 71 72 0 74 75 76
[1]+ Done od -An -td1 < /root/pipe
bash의 이러한 동작을 변경할 수 있는 방법이 있습니까? 아니면 0바이트를 어떻게 읽을 수 있나요?
답변1
bash
변수는 NUL 바이트를 저장할 수 없습니다( zsh
NUL 바이트만 저장할 수 있지만 ksh93
's 도 참조 printf %B
하고 typeset -b
base64 인코딩을 사용하세요). 내장 함수 는 read
입력에서 NUL 바이트도 건너뜁니다.
그러나 여기서는 다음을 사용할 수 있습니다.
LC_ALL=C IFS= read -rd '' -n1 c
즉, NUL로 구분된 레코드에서 최대 1바이트를 읽습니다. 따라서 비어 있으면 EOF(그러나 종료 상태는 0이 아님) 또는 NUL 바이트를 읽었음을 $c
의미합니다 .read
두 경우 모두 다음을 사용하여 바이트의 숫자 값을 얻을 수 있습니다.
LC_ALL=C printf -v value %d "'$c"
그래서:
while
IFS= LC_ALL=C read -rd '' -n1 c &&
LC_ALL=C printf -v value %d "'$c"
do
echo "Got byte with value $value"
done
EOF까지 한 번에 한 바이트씩 읽고 NUL 바이트를 지원합니다.
아니면 이렇게 할 수도 있습니다:
value=$(dd bs=1 count=1 2> /dev/null | od -An -vtu1)
또는 일부 od
구현을 통해:
value=$(od -N1 -An -vtu1)
icanon
이는 추가 프로세스를 분기하고 외부 실행 파일을 실행하는 것을 의미하지만(stdin이 터미널 장치인 경우 모드 에서 벗어나지 않습니다 read
).