First look at how "sed" is splitting up your file into individual records:
sed -n 'l' < infile.txt
MSH|...\rLine 2|...\rLine 3|...\rLine N|...$
MSH|...\rLine 2|...\rLine 3|...\rLine N|...$
that means the "\r\n" combo at the end of record is eaten.
Remember that "sed" implicitly places a "\n" when printing.
sed -e '
s/^/\x0B/; # prefix record with a vertical tab
s/$/\x1C\x0D/; # suffix record with FS+CR AND sed will add a \n of its own
' < infile.txt | tr -d '\n' > outfile.txt
Or equivalently you can write like as below:
sed -e 's/.*/\x0B&\x1C\x0D/' < infile.txt | tr -d '\n' > outfile.txt
N.B.: outfile.txt will have no newlines.
Also note that there was a typo in your sed code in \0D in the replacement
portion of the second s/// statement. It helps if you choose a different
delimiter to the s/// statement other than #. The global flag to the s///
statements are superfluous since the s/// happen once at the end in one s///
and at the beginning in the other s/// for each record.
> sed -e 's#^MSH#\x0BMSH#g' -e 's#\x0D\x0A#\x1C\0D#g'
You could do it staying within bash also:
# constants defined
eval "`echo 'VT=qnq' | tr 'qn' '\47\13'`"
eval "`echo 'CR=qnq' | tr 'qn' '\47\15'`"
eval "`echo 'FS=qnq' | tr 'qn' '\47\34'`"
while IFS= read -r record
do
record=$VT${record%?}$FS$CR
printf '%s' "$record"
done < infile.txt > outfile.txt