How can I make my bash script open cat for input, and then save input to a variable in the script

I am trying to make a simple email script so that other users can email me from the terminal.

The script is being made partly as a learning experience, and party because the other users are not very linux savvy, so I want them to easily be able to email from terminal, without having to learn the programs, and syntax.

I have ubuntu 16.04.1 Server

So far this is what I am working with:

clear
echo -e "Please Enter Subject of email:\n "
read subject
echo -e "\n\nFrom: $USER\nTo: Adminstrator\nSubject: $subject\n\nEnter body of email: \n "
read body
echo -e "\nYour message is as follows:\n"
echo -e "\nFrom: $USER\nTo: Administrator\nSubject: $subject\n\n"
echo -e "$body \n\n"
read -p "Send to Administrator (y/n)?" choice
case "$choice" in y|Y ) echo "$body" | mail -s "$subject" ;; n|N ) echo "Roger Dodger. Email canceled";; * ) echo "invalid";;
esac

Things it can do:

  • request input for subject and body

  • send input to their respective variables.

  • call those variables, and send the email.

Things I want it to be able to do:

  • Allow pressing enter to go to a new line

  • Allow backspace

I have been everywhere twice, and I assume I am missing something, or lack some fundamental knowledge about how I can incorporate these features. I have tried using read with delimiters, cat with delimiters while loops (whatever that is) I have setup variable, aliases. I have read man pages I have tried piping it and substituting with $() I have tried sending the input to a file and calling that file.

Iam running out of ideas.

I could not get the terminal provide a a section to type in at all when using cat, but I could get it to provide the prompt with read.

I am thinking I want similar to

cat >> SEND && echo | ${BODY) 

and then where the script calls for it, just provide the ${BODY} variable.

In a terminal by itself, I successfully ran:

cat << SEND && echo | ${BODY} && echo "${BODY}"

which allowed me to type multiple lines, until I typed SEND, and the pasted the ${BODY} variable whos output was correct.

Any ideas are apreciated.

7

1 Answer

I don't think what you're asking for is possible. When using read, you only have access to very minimal text editing abilities, it simply isn't designed for what you want it to do. Even if you can find a way to allow backspace and newlines, it is still a very cumbersome way of asking your users to provide input. It is very rarely a good idea to expect your users to type text directly into the running program. I suggest an alternative:

  1. Have your script read the subject from the command line.
  2. Have it read the body from an input file.

That way, your user doesn't need to type everything out manually, your script can be automated to send multiple emails, greatly increasing its usefulness and your users don't need to start everything again from scratch if they make a typo. Finally, they can format the email body as they want. So, for example, you can do something like this:

#!/bin/bash
## Parse command line options.
while getopts ":s:f:" opt; do case $opt in s) subject="$OPTARG" ;; f) file="$OPTARG" ## Exit if the file isn't a file or isn't readble if [[ ! -r "$file" && ! -f "$file" ]]; then echo "File doesn't exist or isn't readble" exit fi ;; \?) echo "Invalid option: -$OPTARG" >&2;; esac
done
## Read the email body
body=$(cat "$file")
## Inform the user. The "\033[1m" starts bold formatting and the
## "\033[0m" ends it. Remove them if you don't want bold.
echo -e "\033[1mYour message is as follows:\033[0m"
cat<<EoF
From: $USER
To: Administrator
Subject: $subject
$body
------------------
EoF
read -p "Send to Administrator (y/n)?" choice
case "$choice" in y|Y ) echo "$body" | mail -s "$subject" ;; n|N ) echo "Roger Dodger. Email canceled";; * ) echo "invalid";;
esac

Then, you give it the subject and an input file. For example, if you have a file called message with the following contents:

$ cat message
Dear John,
I hope this email finds you well. I am writing to inquire about the
price of the bridge you are selling. I would love to have a bridge
like that in my garden since I think it would make my cows look
larger.
Looking forward to hearing from you,
best,
Jack. 

You would run the script like this:

$ foo.sh -s "about that bridge..." -f message
Your message is as follows:
From: terdon
To: Administrator
Subject: about that bridge...
Dear John,
I hope this email finds you well. I am writing to inquire about the
price of the bridge you are selling. I would love to have a bridge
like that in my garden since I think it would make my cows look
larger.
Looking forward to hearing from you,
best,
Jack.
------------------
Send to Administrator (y/n)?

Alternatively, if you insist on having the users write the message on the fly, you could use the default editor available on your system:

#!/bin/bash
clear
echo -e "Please Enter Subject of email:\n "
read subject
## create a temp file
tmpfile=$(mktemp)
cat<<EoF
Press Enter to open an editor where you can write the body of the email.
When finished, save and exit.
EoF
read
## Open the editor
"$EDITOR" "$tmpfile"
## Read the body and delete the tmp file
body=$(cat "$tmpfile")
rm "$tmpfile"
## Inform the user. The "\033[1m" starts bold formatting and the
## "\033[0m" ends it. Remove them if you don't want bold.
echo -e "\033[1mYour message is as follows:\033[0m"
cat<<EoF
From: $USER
To: Administrator
Subject: $subject
$body
EoF
read -p "Send to Administrator (y/n)?" choice
case "$choice" in y|Y ) echo "$body" | mail -s "$subject" ;; n|N ) echo "Roger Dodger. Email canceled";; * ) echo "invalid";;
esac

Finally, if you insist on making your life and that of your users more difficult than it needs to be, you can use cat > $tmpfile to write the body to the tmpfile, tell your users to hit Ctrl+D when they've finished writing:

#!/bin/bash
clear
echo -e "Please Enter Subject of email:\n "
read subject
## create a temp file
tmpfile=$(mktemp)
## Enter the body
printf '\nPlease enter the body of the email below. Hit Ctrl+D when done.\n\n'
cat > $tmpfile
body=$(cat "$tmpfile")
rm "$tmpfile"
## Inform the user. The "\033[1m" starts bold formatting and the
## "\033[0m" ends it. Remove them if you don't want bold.
echo -e "\033[1mYour message is as follows:\033[0m"
cat<<EoF
From: $USER
To: Administrator
Subject: $subject
$body
EoF
read -p "Send to Administrator (y/n)?" choice
case "$choice" in y|Y ) echo "$body" | mail -s "$subject" ;; n|N ) echo "Roger Dodger. Email canceled";; * ) echo "invalid";;
esac
8

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like