Morse Code with Associative Array

Continuing my quest to learn BASH, Bourne, Awk, Grep, etc. on my own through the use of a few books. I've come to an exercise that has me absolutely stumped.

The specifics:

  1. Using ONLY BASH scripting commands (not sed, awk, etc.), write a script to convert a string on the command line to Morse code. The script will handle only capital letters and numbers
  2. It will convert the string given on the command line as in the
    following example:
    $ ./morse.bash �CAT IN�
    -.-.,.-,-,SP,..,-.,EOT (SP is used for a space, and EOT for end of transmission).
  3. An associative array is to be used for the �lookup table� to do the
    conversion from a character to Morse Code.

This is my time using an associative array, so this exercise has me stumped. Any help, guidance, suggestions are greatly appreciated. Here's what I have so far:

morse=$1
for (( i = 0; $i < ${#morse}; i = $i +1 ));
do
        echo ${morse:$i:1}
done

declare -A morse #Declare associative array
morse[A]=".;-"
morse="-;.;.;."
morse[C]="-;.;-;."
morse[D]="-;.;."
morse[E]="."
morse[F]=".;.;-;."
morse[G]="-;-;."
morse[H]=".;.;.;."
morse=".;."
morse[J]=".;-;-;-"
morse[K]="-;.;-"
morse[L]=".;-;.;."
morse[M]="-;-"
morse[N]="-;."
morse[O]="-;-;-"
morse[P]=".;-;-;."
morse[Q]="-;-;.;-"
morse[R]="-;-;.;-"
morse=".;.;."
morse[T]="-"
morse=".;.;-"
morse[V]=".;.;.;-"
morse[W]=".;-;-"
morse[X]="-;.;.;-"
morse[Y]="-;.;-;-"
morse[Z]="-;-;.;."
morse[1]=".;-;-;-;-"
morse[2]=".;.;-;-;-"
morse[3]=".;.;.;-;-"
morse[4]=".;.;.;.;-"
morse[5]=".;.;.;.;."
morse[6]="-;.;.;.;."
morse[7]="-;-;.;.;."
morse[8]="-;-;-;.;."
morse[9]="-;-;-;-;."
morse[0]="-;-;-;-;-"

Declare the array BEFORE you execute the loop.

And, don't use the same name for a scalar variable and an array variable.

Thank you gentlemen. I'll give that a shot.

Is this the idea?
I put the loop at the end so bash will see the array
as it reads top down. I think that's right...
I'm not sure I got the associative array part right though? echo !${morse[$N]}

declare -A morse #Declare associative array
declare -u input  # Force upper case

morse[A]=".;-"
...
...
morse[0]="-;-;-;-;-"

# Begin here after reading the array
input=$1
for (( i = 0; $i < ${#input}; i = $i +1 ));
do
    N=${input:$i:1}
    echo !${morse[$N]}
done

Potential improvement:

        N=${input:$i:1}

        if [ "$N" = " " ]; then
          printf "%s" SP
        else
          printf "%s" "${morse[$N]}"
        fi
done

printf "%s\n" EOT

Thank you both!

I'd like to get the output to print vertically (I find it easier to read that way), but want to keep the SP between words and the EOT at the end.

Just add a newline character to the printf command

printf "%s\n" SP

Don't forget to do the same for the other printf command between else and fi .
The third printf does not need to be modified.

Hope this will produce the required output.

Thats a fun excercise :smiley:

Here is my test to reverse the input as well:
I mean, it has to be able to translate it both ways, doesnt it? :wink:

+ ~ $ morse "Hello UNIX DOT com"
....;.;.-..;.-..;---;SP;..-;-.;..;-..-;SP;-..;---;-;SP;-.-.;---;--;EOT

:) ~ $ morse "....;.;.-..;.-..;---;SP;..-;-.;..;-..-;SP;-..;---;-;SP;-.-.;---;--;EOT"
HELLO UNIX DOT COM 
EOT

:) ~ $ morse -l "....;.;.-..;.-..;---;SP;..-;-.;..;-..-;SP;-..;---;-;SP;-.-.;---;--;EOT"
HELLO 
UNIX 
DOT 
COM 
EOT
:) ~ $ 

Show me yours, i'll show you mine :stuck_out_tongue:

-;.-;-;--SP-;.;.;..;--;.;.SPSP.;.;.;...;.;.;..SPSP.;-;.;.-;-;--;-;--;.;-.;.-;.-;-;.SP.;.;-;.-;-;--;-;.;-.;-;-.;--;-;.;--;.;.SP--;-;-SP.;.;...SP-.;.;.;..SP-;.;-;.-;-;--;.;..EOT

Thank you kind sir!

I must say - for a novice trying to learn Unix, this board has been a godsend. I continue to be blown away by the number of people willing to help. Not only that, but they're always polite and welcoming toward new members. Thank you!!

Note that i 'had' to change the morse-codes per letter to be without a ; , furthermore it requires now a ; before SP (read: after every letter).
But 'forcing' that, one can switch between 2 output types, all on one line, or each word a seperate line.

morse "--;.-;-.--;SP-;....;.;SP..-.;---;.-.;-.-.;.;SP-...;.;SP.--;..;-;....;SP-.--;---;..-;EOT"
morse ".-;-.;-..;SP..;SP....;---;.--.;.;SP-;....;..;...;SP.--;.-;...;SP-.;---;SP....;---;--;.;.--;---;.-.;-.-;EOT"

:cool: :stuck_out_tongue:

EDIT:
Bleh, me alrady scripting way too much..
But thanks for the mind break :slight_smile:

Now you're just showing off

The bash utility on the current OS X (GNU bash, version 3.2.53(1)-release (x86_64-apple-darwin14)) does not support associative arrays. With a 1993 or later version of the Korn shell, you could try something like:

#!/bin/ksh
Morse=( [A]=".-," ="-...," [C]="-.-.," [D]="-..," [E]=".," [F]="..-.,"
	[G]="--.," [H]="....," ="..," [J]=".---," [K]="-.-," [L]=".-..,"
	[M]="--," [N]="-.," ["O"]="---," [P]=".--.," [Q]="--.-," [R]="--.-,"
	="...," [T]="-," ="..-," [V]="...-," [W]=".--," [X]="-..-,"
	[Y]="-.--," [Z]="--..," [0]="-----," [1]=".----," [2]="..---,"
	[3]="...--," [4]="....-," [5]=".....," [6]="-....," [7]="--...,"
	[8]="---..," [9]="----.," [ ]="SP," [.]="STOP," )

while [ $# -gt 0 ]
do	arg="$1"
	for (( i = 0; i < ${#arg}; i++ ))
	do	printf '%s' "${Morse["${arg:i:1}"]}"
	done
	[ $# = 1 ] && printf 'EOT\n' || printf '%s' "${Morse[ ]}"
	shift
done

which could be invoked as:

./morse.ksh SOS "1 2 3" "THIS IS A TEST."

to produce the output:

...,---,...,SP,.----,SP,..---,SP,...--,SP,-,....,..,...,SP,..,...,SP,.-,SP,-,.,...,-,STOP,EOT

If you'd like to change the output from the script I suggested to look like:

...,---,...,SP
.----,SP
..---,SP
...--,SP
-,....,..,...,SP
..,...,SP
.-,SP
-,.,...,-,STOP,EOT

instead of what I showed before, change the line in that script:

	[8]="---..," [9]="----.," [ ]="SP," [.]="STOP," )

to:

	[8]="---..," [9]="----.," [.]="STOP," [ ]="SP
"  )

If i did, it was by accident just because i had fun and got excited as it was and is also a challenge to me.
And it is a communication tool, so the 'encoding' must be possible both ways.

morse SOS. "1 2 3." "THIS IS A TEST."
...;---;...;STOPSP.----;SP..---;SP...--;STOPSP-;....;..;...;SP..;...;SP.-;SP-;.;...;-;STOPSPEOT
morse -l "...;---;...;STOPSP.----;SP..---;SP...--;STOPSP-;....;..;...;SP..;...;SP.-;SP-;.;...;-;STOPSPEOT"
SOS 
STOP
 
1 
2 
3 
STOP
 
THIS 
IS 
A 
TEST 
STOP
 



EOT

Ok, vice-versa encoding is working now:

morse -q SOS. "1 2 3." "THIS IS A TEST."|while read line;do morse -l "$line";done

SOS 
STOP
 
1 
2 
3 
STOP
 
THIS 
IS 
A 
TEST 
STOP
 
EOT

This stuff is really a good training excercise for shuffeling and parsinge strings and chars.
But by now, WAY too many hours invested in this, mostly just to get the output/handling as it looks now...

#!/bin/bash
# ------------------------------------------------------------------------
#
# Copyright (c) 2014 by Simon Arjuna Erat (sea)  <erat.simon@gmail.com>
# All rights reserved.
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>
#
# ------------------------------------------------------------------------
#
#	Description:	  Translates STRING to MORSE and vice-versa
#	Resource:	  http://www.unix.com/shell-programming-and-scripting/253424-morse-code-associative-array.html
#	Resource:	  http://en.wikipedia.org/wiki/Morse_code
#	Original author:  ksmarine1980
#
#	Variables
#
	ME=${0##*/}
	ME=${ME/.sh/}
	script_version=0.6
	declare -A morse  # Declare associative array
	declare -A letter  # Declare associative array
	declare -u input  # Force upper case
	SKIP=0		  # Skip this many 'chars' :: SP, print space at SKIP=1
	STRING=""	  # Contains the current signs for a char
	NL=""		  # Newline for final linebreak: EOT
	LB=""		  # Fixed linebreak after a word?
	EOT=true	  # Show EOT after each call, very annoying while reading a file with just a word list
	
	morse[A]=".-"	;	morse="-..."	;	morse[C]="-.-."
	morse[D]="-.."	;	morse[E]="."	;	morse[F]="..-."
	morse[G]="--."	;	morse[H]="...."	;	morse=".."
	morse[J]=".---"	;	morse[K]="-.-"	;	morse[L]=".-.."
	morse[M]="--"	;	morse[N]="-."	;	morse[O]="---"
	morse[P]=".--."	;	morse[Q]="--.-"	;	morse[R]=".-."
	morse="..."	;	morse[T]="-"	;	morse="..-"
	morse[V]="...-"	;	morse[W]=".--"	;	morse[X]="-..-"
	morse[Y]="-.--"	;	morse[Z]="--.."	;	morse[1]=".----"
	morse[2]="..---";	morse[3]="...--";	morse[4]="....-"
	morse[5]=".....";	morse[6]="-....";	morse[7]="--..."
	morse[8]="---..";	morse[9]="----.";	morse[0]="-----"
	morse[ ]="SP"	;	morse[.]="STOP"
#
#	Options
#
	for A in "${@}"
	do	case "$A" in
		-l)	LB="\n"	
			shift	;;
		-q)	EOT=false
			shift	;;
		-h|--help)
			echo "
$ME ($script_version)
Usage:	$ME [options] \"STRING\"

\"STRING\" can be either a word or morse code.
Either way it could also be a line-feed.

Where options are:
[-l]	Print one word per line
[-q]	Quiet, print no EOT upon exit
"
			exit
			;;
		esac
	done
#
#	Functions OR the Array
#
#	${letter["MORSECODE"]} vs. $(morse2char "MORSECODE")
#	Note that i used the function since i had forgotten to declare the 'letter' array at first,
#	so it didnt work upon the first try.
#
	morse2char() { # "...--"
	# Expects a string with dots and dashes which as whole represents a single character
	# Prints the according letter, or a question mark if nothing matches
		CODE="$1"
		case "$CODE" in
		".-")		printf A	;;
		"-...")		printf B	;;
		"-.-.")		printf C	;;
		"-..")		printf D	;;
		".")		printf E	;;
		"..-.")		printf F	;;
		"--.")		printf G	;;
		"....")		printf H	;;
		"..")		printf I	;;
		".---")		printf J	;;
		"-.-")		printf K	;;
		".-..")		printf L	;;
		"--")		printf M	;;
		"-.")		printf N	;;
		"---")		printf O	;;
		".--.")		printf P	;;
		"--.-")		printf Q	;;
		".-.")		printf R	;;
		"...")		printf S	;;
		"-")		printf T	;;
		"..-")		printf U	;;
		"...-")		printf V	;;
		".--")		printf W	;;
		"-..-")		printf X	;;
		"-.--")		printf Y	;;
		"--..")		printf Z	;;
		".----")	printf 1	;;
		"..---")	printf 2	;;
		"...--")	printf 3	;;
		"....-")	printf 4	;;
		".....")	printf 5	;;
		"-....")	printf 6	;;
		"--...")	printf 7	;;
		"---..")	printf 8	;;
		"----.")	printf 9	;;
		"-----")	printf 0	;;
		"SP")		printf " "	;;
		# NOTE that for 'style' reasons, i wanted to keep the word 'STOP' when printing words.
		#"STOP")		printf "."	;;
		*)		printf "$CODE?"	;;
		esac
	}
	letter[".-"]=A	;	letter["-..."]=B;	letter["-.-."]=C
	letter["-.."]=D	;	letter["."]=E	;	letter["..-."]=F
	letter["--."]=G	;	letter["...."]=H;	letter[".."]=I
	letter[".---"]=J;	letter["-.-"]=K	;	letter[".-.."]=L
	letter["--"]=M	;	letter["-."]=N	;	letter["---"]=O
	letter[".--."]=P;	letter["--.-"]=Q;	letter[".-."]=R
	letter["..."]=S	;	letter["-"]=T	;	letter["..-"]=U
	letter["...-"]=V;	letter[".--"]=W	;	letter["-..-"]=X
	letter["-.--"]=Y;	letter["--.."]=Z;	letter[".----"]=1
	letter["..---"]=2;	letter["...--"]=3;	letter["....-"]=4
	letter["....."]=5;	letter["-...."]=6;	letter["--..."]=7
	letter["---.."]=8;	letter["----."]=9;	letter["-----"]=0
	letter["SP"]=" ";	letter["STOP"]="."
#
#	Action
#
	[[  -z $LB ]] && NL="" || NL="$LB"
	while [ $# -gt 0 ];do
		# Now that the options are parsed, we can set the input to the current argument
		input="$1"
		if [[ "." = "${input:0:1}" ]] || [[ "-" = "${input:0:1}" ]]
		then	# Its morse to letters
			for (( i = 0; $i < "${#input}"; i = $i +1 ))
			do	CHAR="${input:$i:1}"
				#  Enable NewLine if LineBreak is active
				[[  -z $LB ]] && NL="" || NL="$LB"
				if [[ $SKIP -gt 0 ]]
				then	# Skip this many times
					[[  -z $LB ]] && NL="" || NL="$LB"
					STRING+="$CHAR"
					SPACE=" "
					# Do action according to SPECIAL word, or part of it.
					case "$STRING" in
					SP)	printf "%s" "$(morse2char $STRING)"
						STRING=""
						SPACE=""	;;
					ST)	SKIP=2		;;
					STOP)	printf "%s" "$(morse2char $STRING)"
						#printf "$NL"
						STRING=""	;;
					esac
					[[ $SKIP -eq 1 ]] && printf "$SPACE$NL" && NL=""
					SKIP=$(($SKIP-1))
				else	# Decide action upon current 'CHAR', or SIGN respectivly
					case "$CHAR" in
					S)	# Make sure there is no accidental line break
						SKIP=1
						STRING="$CHAR"
						;;
					E)	# Make line break at End Of Transmission
						SKIP=3 ; NL="\n" 
						;;
					";")	# Word-end, print it and clean it
						[[ -z "$STRING" ]] || printf $(morse2char "$STRING")
						STRING=""
						;;
					*)	# Add char to word
						STRING+="$CHAR"
						;;
					esac
				fi
				# Print STOP and optional a new line, if linebreak is active
				# Note that for style reasons i want to keep the word STOP, rather than the dot char/sign.
				[[ STOP = $STRING ]] && printf "$STRING$NL" && STRING=""
			done
			# 'WORD' is done...
			# Print a new line, if linebreak is active
			printf "$NL"
		else	# Its letters to morse
			for (( i = 0; $i < "${#input}"; i = $i +1 ))
			do	N=${input:$i:1}
				case "$N" in
				" ")	printf "%s$NL" "SP"	;;
				".")	printf "%s$NL" "STOP"	;;
				*)	printf "%s" "${morse[$N]};" ;;
				esac
			done
			# Print 'SP'ace and a new line, if linebreak is active
			printf "SP$LB"
		fi
		# Skip to next 'WORD', print a new line, if linebreak is active
		printf "$NL"
		# Remove current argument $1
		shift
	done
	# All is done, show EOT unless its quiet (helps while reading lines from a text file)
	$EOT && printf "$NL%s\n" EOT || printf "\n"

Play with it, change the usage of the function morse2char to be using the letter["..."] array.
Make your own experiments.
Make one script to encode, and another to decode, then try to combine them.

Hope you like it

I've run into one small issue with the space (SP) character. On the command line, if I type ./morse.bash "CAT IN" the output is -.-.,.-,-,SP..,-.,EOT. I can't figure out why two .. are following the SP. Here's my code:

morse[A]=".-,"
sorsssB]="-...,"
sorse[C]="-.-.,"
sorssss]="-..,"
sorsssE]=".,"
sorse[F]="..-.,"
morse[G]="--.,"
morse[H]="....,"
morse="..,"
morse[J]=".---,"
morse[K]="-.-,"
morse[L]=".-..,"
morse[M]="--,"
morse[N]="-.,"
morse[O]="---,"
morse[P]=".--.,"
morse[Q]="--.-,"
morse[R]="--.-,"
morse="...,"
morse[T]="-,"
morse="..-,"
morse[V]="...-,"
morse[W]=".--,"
morse[X]="-..-,"
morse[Y]="-.--,"
morse[Z]="--..,"
morse[1]=".----,"
morse[2]="..---,"
morse[3]="...--,"
morse[4]="....-,"
morse[5]=".....,"
morse[6]="-....,"
morse[7]="--...,"
morse[8]="---..,"
morse[9]="----.,"
morse[0]="-----,"

input=$1
for (( i = 0; $i < ${#input}; i = $i + 1 ));
do
        N=${input:$i:1}

        if [ "$N" = " " ]; then
                printf "%s" SP
        else
                printf "%s" "${morse[$N]}"
        fi
done
printf "%s\n" EOT

That is because you printf "SP" without a comma. In fact, it's the ${morse["I"]} following the space in input.

---------- Post updated at 19:31 ---------- Previous update was at 18:56 ----------

In fact, if you add morse[ ]="SP" to your array (as already proposed by Don Cragun), the if ... then ... fi becomes unnecessary:

for (( i = 0; $i < ${#input}; i = $i + 1 ));
        do printf "%s " "${morse[${input:$i:1}]}"
        done

As an addendum...
This example only produces the number 2 at about 8 WPM through the sound system...
For this particular example SOX will be required.

#!/bin/bash
# Working idea, Barry walker, G0LCU...
# Morse.sh
# Sounder for Morse at about 8 WPM...
# Output can be used to modulate an SSB HF transceiver...
# OSX 10.7.5, default bash terminal AND SOX.
# Just as easily do cat /tmp/sample.raw > /dev/dsp for machines with /dev/dsp.
data="\\x80\\x26\\x00\\x26\\x7F\\xD9\\xFF\\xD9"
sample=0
> /tmp/dit.raw
> /tmp/dah.raw
chmod 644 /tmp/dit.raw
chmod 644 /tmp/dah.raw
for sample in {0..6}
do
        data=$data$data
done
printf "$data" >> /tmp/dit.raw
printf "$data" >> /tmp/dah.raw
printf "$data" >> /tmp/dah.raw
printf "$data" >> /tmp/dah.raw
# An example of the Morse number 2...
/Users/barrywalker/sox-14.4.0/sox -r 8000 -b 8 -c 1 -e unsigned-integer /tmp/dit.raw -d > /dev/null 2>&1
/Users/barrywalker/sox-14.4.0/sox -r 8000 -b 8 -c 1 -e unsigned-integer /tmp/dit.raw -d > /dev/null 2>&1
/Users/barrywalker/sox-14.4.0/sox -r 8000 -b 8 -c 1 -e unsigned-integer /tmp/dah.raw -d > /dev/null 2>&1
/Users/barrywalker/sox-14.4.0/sox -r 8000 -b 8 -c 1 -e unsigned-integer /tmp/dah.raw -d > /dev/null 2>&1
/Users/barrywalker/sox-14.4.0/sox -r 8000 -b 8 -c 1 -e unsigned-integer /tmp/dah.raw -d > /dev/null 2>&1

This one accepts input from a pipe or interactive stdin or with a filename as argument. See Usage:
I'm struggling with strings as arguments to the command. It throws an error if $1 is not a filename. I managed to get it to accept option "-h", but dictionary words don't fly (yet).

#!/bin/bash
#
# mors2.sh -- requires Bash 4+

usage ()
{
    echo " Usage:
    Command line mode -- no quotes needed:
        \$ `basename $0` -- Type text/code [Enter]
        ["=" key] [ctrl+C] [ctrl+D] to exit this mode
    Pipe modes:
        \$ `basename $0` [filename] [options]
        \$ echo [morse string] [text string] | `basename $0`
        \$ cat [filename] | `basename $0`

    Options:
        -h) This message
        *)"
    exit
}

declare -A alpha #Declare associative array
declare -A morse #Declare associative array
declare -u text  #Force upper case

alpha=(
 [A]='.-'     ='-...'     [C]='-.-.'     [D]='-..'     [E]='.'
 [F]='..-.'     [G]='--.'     [H]='....'     ='..'     [J]='.---'
 [K]='-.-'     [L]='.-..'     [M]='--'     [N]='-.'     [O]='---'
 [P]='.--.'     [Q]='--.-'     [R]='.-.'     ='...'     [T]='-'
 ='..-'     [V]='...-'     [W]='.--'     [X]='-..-'     [Y]='-.--'
 [Z]='--..'
 [0]='-----'     [1]='.----'     [2]='..---'     [3]='...--'     [4]='....-'
 [5]='.....'     [6]='-....'     [7]='--...'     [8]='---..'     [9]='----.'
) 

morse=(
 [.-]='A'     [-...]='B'     [-.-.]='C'     [-..]='D'     [.]='E'
 [..-.]='F'     [--.]='G'     [....]='H'     [..]='I'     [.---]='J'
 [-.-]='K'     [.-..]='L'     [--]='M'     [-.]='N'     [---]='O'
 [.--.]='P'     [--.-]='Q'     [.-.]='R'     [...]='S'     [-]='T'
 [..-]='U'     [...-]='V'     [.--]='W'     [-..-]='X'     [-.--]='Y'
 [--..]='Z'
 [-----]='0'     [.----]='1'     [..---]='2'     [...--]='3'     [....-]='4'
 [.....]='5'     [-....]='6'     [--...]='7'     [---..]='8'     [----.]='9'
)

textin ()
{
    for text in "$@";
    do
        for (( i = 0; $i < ${#text}; i = $i +1 ));
        do
            N=${text:$i:1}
            printf "$txt_fmt" "${alpha[$N]}" "$N"
        done
    done
}
 
morsein ()
{
    for code in "$@";
    do
        if [ $code == $wrd_sep ]; then
            echo 'SP'
        else
            printf "$cod_fmt" "$code" "${morse[$code]}"
        fi
    done
}

pipein ()
{
printf " %s\n\n" "#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 # Type text and/or morse code.
 # When mixing morse code and text, separate words with '+'.
 # Enter '=' to exit.
 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
declare -a ary
while read line
do
    [[ $line =~ ^$xit ]] && echo "Bye" && exit
    ary=($(echo $line | tr ' ' '\n'))
    sz=${#ary
[*]}
    for wrds in ${ary
[*]};
    do
        I=${wrds:0:1}
        if [[ "$I" =~ ^[[:alnum:]] ]]; then
            textin "$wrds"
            [[ $sz -gt 1 || ${wrds: -1} == '.' ]] && echo 'SP'
        elif [[ $I =~ ^[-|.|$wrd_sep] ]]; then
            morsein "$wrds"
        fi
        sz=$(( $sz -1 ))
    done
    printf "%s\n\n" "EOT"

# done < "${1:-/proc/${$}/fd/0}"
done < ${1:-/dev/stdin}
echo " Bye"
}

options ()
{
    case "$@" in
        -h) usage ;;
        -*) usage ;;
    esac
}

# Start here
############
txt_fmt=" %s\t%s\n"
cod_fmt=" %s\t%s\n"
wrd_sep='+'    # char used to separate words when typing morse code
xit='='      # char to exit interactive console mode

if [[ $1 =~ ^-[[:alpha:]]$ ]]; then
    options "$1"
else
    pipein "$@"
fi
exit

# eof #