3

I have a code.txt file that contains morse code for example

.- .-.

I have a function called decode inside a bash file called morse as this:

decode (){ 
   sed -i 's/ \.-/A/g' $1
   sed -i 's/ \.-./R/g' $1
   cat $1
}

When I type in terminal $bash morse decode code.txt

I receive:

AA.

The output I want is :

AR

How can it see separate that the string .- is A and the .-. is R?

3
  • 1
    First, run sed -i 's/ \.-\./R/g' $1 Commented Feb 6, 2020 at 14:58
  • 1
    Run a single sed like this: sed -i 's/ \.-\./R/g; s/ \.-/A/g' "$1" Commented Feb 6, 2020 at 15:00
  • If all you are trying to do is output the translation to stdout, there is no need to edit the file or use cat. You could just run the combined sed anubhava suggested without the -i option. Then the output will go to stdout without the use of cat. Then you can use your function like this: decode code.txt > decoded.txt Commented Feb 6, 2020 at 15:06

4 Answers 4

1

If your intention is to encode and decode Morse messages with any tool then something like this will do :

#!/usr/local/bin/python3
import re

alphabet = { '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':'--..', '1':'.----', '2':'..---', '3':'...--', '4':'....-', '5':'.....', '6':'-....', '7':'--...', '8':'---..', '9':'----.', '0':'-----', ', ':'--..--', '.':'.-.-.-', '?':'..--..', '/':'-..-.', '-':'-....-', '(':'-.--.', ')':'-.--.-',' ':'  '} 

def encode(message): 
    return "".join([ ( alphabet[letter.upper()] + ' ' ) if letter != ' ' else '  ' for letter in message])

def decode(message):
    return "".join([ list(alphabet.keys())[list(alphabet.values()).index(item if item != '|' else '  ')] for item in re.sub(r' {2,}', ' | ',message).split(' ')])

print(encode('THIS IS FINE'))
print(decode('- .... .. ...   .. ...   ..-. .. -. .'))

Hope it helps too.

Sign up to request clarification or add additional context in comments.

3 Comments

That a good effort. I am searching for something like that but in a bash file with unix not in python..I would appreciate if you can help me there.
@P.Bes Well you are in the right track if thats your goal. sed looks like a good start. Let me see how much of that Python script I can translate to Bash. Can you use awk at least? or you need pure bash?
pure bash I think
1

Wow interesting idea! Based on @MatiasBarrios alphabet i made this.

#!/bin/bash

string=$1

declare -A 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]='--..'

    [1]='.----'  [2]='..---'  [3]='...--'  [4]='....-'  [5]='.....'
    [6]='-....'  [7]='--...'  [8]='---..'  [9]='----.'  [0]='-----'
    [(]='-.--.'  [)]='-.--.-' [/]='-..-.'  [-]='-....-' [+]='.-.-.'
    [.]='.-.-.-' [,]='--..--' [?]='..--..' [!]='-.-.--' [ ]='  '
)

morse () {
    while [[ "$string" ]]; do
        symbol="${string::1}"
        printf -- "${morse["${symbol^}"]} "
        string="${string:1}"
    done
}

demorse () {
    declare -A demorse
    for item in "${!morse[@]}"; { demorse["${morse["$item"]}"]="$item"; }
    while [[ $@ ]]; do
        printf -- "${demorse["$1"],}"
        shift
    done
}

case $string in
    demorse) shift; demorse "$@";;
    *      )          morse     ;;
esac

Usage

$ ./morse 'hello world!'
.... . .-.. .-.. ---    .-- --- .-. .-.. -.. -.-.--

Demorse also worsk but, spaces have to be printed like this ' '

$ ./morse demorse .... . .-.. .-.. --- '  ' .-- --- .-. .-.. -.. -.-.--
hello world!

Comments

0

You need to run s/ \.-\./R/g replacement first. Note the second . must be escaped to only match a dot.

Hence, use

sed 's/ \.-\./R/g;s/ \.-/A/g' file

See the online demo

Or, another way:

sed -e 's/ \.-\./R/g' -e 's/ \.-/A/g' file

Replace the file with "$1" in your code.

UPDATE

Here is the translation of encoding / decoding Python function posted by Matias below:

#!/bin/bash

### Encoding:

declare -A 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]='--..' [1]='.----' [2]='..---' [3]='...--' [4]='....-' [5]='.....' [6]='-....' [7]='--...' [8]='---..' [9]='----.' [0]='-----' [',']='--..--' ['.']='.-.-.-' [';']='-.-.-.' [':']='---...' ['?']='..--..' ['!']='-.-.--' ['/']='-..-.' ['-']='-....-' ['+']='.-.-.' ['(']='-.--.' [')']='-.--.-' ['_']='..--.-' ['"']='.-..-.' ["'"]='.----.' ['$']='...-..-' ['@']='.--.-.' ['&']='.-...' ['  ']=' '  )

function encode {
  res=''
  s="$1"
  for (( i=0; i<${#s}; i++ )); do
    letter="${s:$i:1}"
    if [[ "$letter" == ' ' ]]; then
      res="${res}  "
    else
      res="${res}${MORSE[${letter^^}]} ";
    fi
  done
  printf "%s" "$res"
}

echo "$(encode "THIS IS FINE")"

### Now, decoding

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

function decode {
  res=''
  tmp="$(sed 's/ \{2,\}/ | /g' <<< "$1")";
  for word in $tmp; do
    if [[ "$word" == '|' ]]; then
      res="${res}${MORSEDEC['  ']}";
    else
      res="${res}${MORSEDEC[$word]}";
    fi
  done
  printf "%s" "$res"
}
echo "$(decode "- .... .. ...   .. ...   ..-. .. -. .")"

See Bash demo online.

2 Comments

Yes but that was an example..What can I do in the case of having all letters of alphabet..For example also "L" is .-.. this means that I must do the same for L
@P.Bes That is the same idea: the longer patterns should be handled before the shorter.
0

The easy answer in RE engines that support look-ahead and look-behind would be to treat the spaces as look-ahead and look-behind triggers, but sed does not support this.

Another option that avoids needing to order the letters is to inject extra symbols to help you mark each letter. Say we inject = round each space, then we can replace delimited sequences in any order, and finally get rid of the delimiters:

echo  .- .-.|sed -e 's/^\(.*\)$/=\1=/;s/ /= =/g' -e 's/=\.-\.=/=R=/g;s/=\.-=/=A=/g' -e 's/= =//g;s/^=//;s/=$//'

If you have rules that need to preserve multiple spaces, then that can be accommodated.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.