UNIX Shell: Combining Multiple Data Streams


Sometimes one needs to compose a binary data stream from different sources. For instance, there may be a need to pass an output from several different utilities, as a single sequence, through a pipe.

The following function, xcat, is a flexible way of achieving that goal:

 1 write_hex ()
 2 {
 3      echo -n "${1}" \
 4              | sed -e 's/\([[:xdigit:]][[:xdigit:]]\)/\\\\x\1/g' \
 5              | xargs printf
 6 }
 7
 8 xcat ()
 9 {
10      local fmt="${1}"
11      local i=0
12
13      shift
14      while [ "${i}" -lt "${#fmt}" ]; do
15              case "$(echo -n "${fmt}" | cut -b "$((${i} + 1))")" in
16                      s) printf '%s' "${1}" ;;
17                      x) write_hex "${1}" ;;
18                      p) cat "${1}" ;;
19                      e) eval ${1} ;;
20              esac
21              i="$((${i} + 1))"
22              shift
23      done
24 }

The function accepts a variable number of arguments. The first argument controls the interpretation of the rest:

The following example outputs the string Hello, world, followed by two bytes CR and LF, followed by ten zero bytes, followed by the name of the operating system, followed by the contents of of fstab(5):

xcat sxeep 'Hello, world' \
    0D0A \
    'dd if=/dev/zero bs=1 count=10 2>/dev/null' \
    "uname -s | tr -d '\\n'" \
    /etc/fstab

The following is the hexadecimal dump of the first 64 bytes of the output of the example given above:

00000000  48 65 6c 6c 6f 2c 20 77  6f 72 6c 64 0d 0a 00 00  |Hello, world....|
00000010  00 00 00 00 00 00 00 00  4f 70 65 6e 42 53 44 31  |........OpenBSD1|
00000020  33 33 35 62 39 31 37 33  37 62 39 34 34 61 64 2e  |335b91737b944ad.|
00000030  62 20 6e 6f 6e 65 20 73  77 61 70 20 73 77 0a 31  |b none swap sw.1|
00000040

The code above was written to function correctly on most modern UNIX systems. With Bash, it is possible to avoid multiple spawning of cut(1) by replacing the line 15 with the following:

15                   case "${ctrl:${i}:1}" in

Vadim Penzin, September 19th, 2015


I hereby place this article into the public domain.
You are welcome to contact me by writing to howto at this domain.
I publish this information in the hope that it will be useful, but without ANY WARRANTY.
You are responsible for any and all consequences that may arise as the result of using this information.