Skip to content

Instantly share code, notes, and snippets.

@allen-woods
Last active December 24, 2020 00:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save allen-woods/e5de00e7ffec0655f9ebafcdc952f27b to your computer and use it in GitHub Desktop.
Save allen-woods/e5de00e7ffec0655f9ebafcdc952f27b to your computer and use it in GitHub Desktop.
Posix conformant support for synchronous data I/O in a named pipe.

Synchronous Data

All data written and read by these functions is formatted as a multi-line string inside the named pipe. Parsing of this data requires understanding of working with multi-line strings inside shell scripts.

In most cases, piping data to sed without the -i option should suffice.

Usage of pipe_w

$ pipe_w <pipe_name> <double_quoted_data_to_write> [write-flag]

CAUTION:

Sanitization (escaping) of data to be written is currently the responsibility of the end user.

Value of write-flag Meaning
--append Appends write of incoming data to existing data (default).
--overwrite Erases all existing data before writing incoming data.

Usage of pipe_r

$ pipe_r <pipe_name> <item_number> [read-flag]

NOTE:

pipe_r can read all data in the named pipe when 0 is passed as the item_number.

Value of read-flag Meaning
--no-delete All data in pipe persists after read (default).
--item-only Only requested item persists after read. (item_number cannot be 0)
--delete-item Deletes the requested item after read; changes index of remaining items, deletes named pipe once empty. (item_number cannot be 0)
--delete-all All data and named pipe are deleted after read.
#!/bin/sh
# Tested on Alpine 3.10.5+
function pipe_r {
local pipe=${1:-"test"}
local item=${2:-0}
local flag=${3:-"--no-delete"}
local sync=
local data=
# NOTE: Require the pipe to exist so we can read from it.
if [ -p $pipe ] && [[ ! -z $pipe ]]
then
# Extract the contents of the pipe.
sync="$(cat < ${pipe})"
if [ $item -eq 0 ]
then
# Place all `sync` data into requested `data`.
data="${sync}"
elif [ $item -gt 0 ]
then
# Place requested item from `sync` into `data`.
data="$(echo "${sync}" | sed "${item}q;d")"
fi
if [ "${flag}" == "--no-delete" ]
then
# Pass all previous `sync` data back into pipe.
( echo "${sync}" > $pipe & ) > /dev/null 2>&1
elif [ "${flag}" == "--item-only" ] && [ $item -gt 0 ]
then
# Pass only requested `data` (item) back into pipe.
( echo "${data}" > $pipe & ) > /dev/null 2>&1
elif [ "${flag}" == "--delete-item" ] && [ $item -gt 0 ]
then
# Parse the remaining items, if any.
local remaining="$(echo "${sync}" | sed "${item}d")"
if [[ -z $remaining ]]
then
# Delete the now empty pipe, silently.
( rm -f $pipe ) > /dev/null 2>&1
else
# Pass mutated data back into pipe with `item` removed.
( echo "${remaining}" > $pipe & ) > /dev/null 2>&1
fi
elif [ "${flag}" == "--delete-all" ]
then
# Delete the pipe, silently.
( rm -f $pipe ) > /dev/null 2>&1
fi
# Send the requested `data` to stdout.
echo "${data}"
fi
}
#!/bin/sh
# Tested on Alpine 3.10.5+
function pipe_w {
local pipe=${1:-"test"}
local data=${2:-"the quick brown fox jumps over the lazy dog"}
local flag=${3:-"--append"}
local first_run=0
local sync=
if [ ! -p $pipe ]
then
# Create the pipe if it doesn't exist.
mkfifo $pipe
# Set `first_run` for proper data handling below.
first_run=1
fi
if [ $first_run -eq 0 ] && [ "${flag}" == "--overwrite" ]
then
# Empty the pipe completely, and silently.
( ( echo ' ' >> $pipe & ) && echo "$(cat < ${pipe})" ) > /dev/null 2>&1
# Set `first_run` for proper data handling below.
first_run=1
fi
if [ $first_run -eq 0 ] && [[ -z $sync ]]
then
# If we are appending data, front-load contents of pipe.
sync="$(cat < ${pipe})"
fi
for item in $data
do
if [ $first_run -eq 1 ]
then
# Pipe is empty, place first item into `sync`.
sync="${item}"
# Unset `first_run` to indicate start of data collection.
first_run=0
else
# Data has collected at least one thing, append item to `sync`.
sync="$(printf "%s\n" "${sync}" "${item}")"
fi
done
# Silently place contents of `sync` into pipe.
( echo "${sync}" > $pipe & )
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment