Last active
August 6, 2022 23:41
-
-
Save bkw777/ddde771cc85fdd888c7ec74953193d66 to your computer and use it in GitHub Desktop.
Read, store, and reproduce binary data, including nulls, in pure bash with no external executables or even subshells.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# Read binary data, including null bytes, from a serial port, | |
# in pure bash with no external executables nor even subshells, | |
# even though it's not possible to store a null in a shell variable. | |
# Uses globals to avoid forking subshells. | |
# Example, echo -e "\0\0\0" |read FOO or printf -v FOO '%b' "\0\0\0" | |
# FOO will not contain any 0x00 bytes. | |
# Same goes for mapfile/readarray. | |
# What you CAN do is read and store every byte other that null normally, | |
# and you can DETECT when you read a null and record that fact instead of the null byte itself. | |
# Read bytes one at a time from a file or device node until the data stops. | |
# Store each byte as a hex pair in it's own array element. | |
# | |
# When "read" gets a null byte, the variable will be empty, but it will | |
# also be empty when there was no data to read. | |
# | |
# The exit value from "read" discloses when a null-byte was consumed as a delimiter | |
# vs when there was no data and the read command timed out. | |
# $?=0 we got a non-null byte normally | |
# 1 we got a 0x00, and ate it as a delimiter, x is empty but we know to use '00' for this byte | |
# 142 we timed-out, x is empty, and we know to terminate the loop and NOT fill x='00' | |
read_tty () { | |
local -i e ;local LANG=C x ;HEX=() | |
while : ;do | |
IFS= read -t0.1 -r -d'' -n1 -u3 x ;e=$? | |
((e>1)) && break | |
((e)) && x='00' || printf -v x '%02x' "'$x" | |
HEX+=($x) | |
done | |
} | |
############################################################### | |
# main | |
typeset -a HEX=() | |
LANG=C PORT="/dev/ttyUSB0" | |
exec 3<>"$PORT" | |
stty -F "$PORT" 19200 raw pass8 clocal cread -echo crtscts -ixon -ixoff -ixany | |
read_tty | |
# We now have an array HEX[], where each element is a hex pair representing one byte, including nulls. | |
# The binary data can be reconstituted with printf. | |
# copy the array to a string plus one leading space | |
# produces x=" 63 61 71..." | |
x=" ${HEX[*]}" | |
# substitute all the spaces with "\x" | |
# produces "\x63\x61\x71..." | |
# printf that with \x## interpretation | |
# produces "cat..." | |
printf '%b' "${x// /\\x}" >capture.bin | |
# To reproduce the original binary data, the printf output must go to a file | |
# or a device node or piped to another process etc. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment