# 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 "

echo -e "\n\nFrom: $USER\nTo: Adminstrator\nSubject:$subject\n\nEnter body of email: \n "
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" email@gmail.com;;
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 http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_08_02.html http://ss64.com/bash/read.html 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.

• Are you sure you want it to work this way? As a general rule, avoid having your users enter text manually after launching the program. That means i) it's hard to edit and has all the issues you mention in your question; ii) if a user makes a mistake, they need to start again from the beginning; iii) even using heredocs (which are what you're looking for), the user needs to manually type the end marker. Would you be open to alternatives like i) using command line arguments to pass the subject and a file for the email? ii) using GUI tools (if installed) to enter the text instead of the terminal? – terdon Sep 27 '16 at 7:48
• Alternatively consider calling either a terminal text editor such as Nemo or a GUI text editor such as Gedit. When the user exits the editor, then give them the option to cancel, reedit, or send. – L. D. James Sep 27 '16 at 8:22
• @L.D.James yeah, but I doubt the OP has a GUI installed since it's a server. – terdon Sep 27 '16 at 8:54
• @terdon Yea, I figured as much. That's why I mentioned Nemo first. Of course a simple sud apt install gedit would provide the GUI to the users logging in. Just some input for immediate full functionality for arrow keys and editing. While I understand the OP made a reference to learning experience. Many applications are a compilation of the Linux tools on the system. But of course, for terminal experience, I could see a lot of merit in including Nemo in the mix. Thanks for the nudge of the OP's intentions! – L. D. James Sep 27 '16 at 10:03
• @L.D.James fair enough, I added another script to my answer which uses the default $EDITOR. – terdon Sep 27 '16 at 10:11 ## 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
Subject: $subject$body

------------------
EoF

case "$choice" in y|Y ) echo "$body" | mail -s "$subject" email@gmail.com;; 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

## 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
Subject: $subject$body
EoF

case "$choice" in y|Y ) echo "$body" | mail -s "$subject" email@gmail.com;; 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 "

## 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
Subject: $subject$body
EoF

case "$choice" in y|Y ) echo "$body" | mail -s "\$subject" email@gmail.com;;

• @Stevener78 yes, that's because you're running cat <<EoF in the script, so the shell will read the script and look for the EoF in the script. In any case though, please put some serious thought into the idea of not asking your users to type things out manually. Say you get this to work somehow, and the user hits Ctrl+C by mistake after having entered 100 lines of email or whatever. What then? Have you ever seen a program that asks you to enter text (more than a few characters) after it has started running? This is really bad design. My 2nd solution lets you write perfectly well. – terdon Sep 28 '16 at 12:53