5
\$\begingroup\$

I have taught myself some bash and already knew some AppleScript, so I have come up with this SSH chatting tool for OS X users. It allows you to chat from a terminal to another OS X computer.

One problem is that this code has to be located in an executable shell file on the computer of the person receiving the messages in order for it to work. For example if the sshChat.sh is located in ~, you have to go ssh username@adress, then cd ~ and then ./sshChat.sh and I would like it to work without the file being on the computer of the person receiving the messages.

VER="1.6 BETA"
echo "#############################"
echo "  SSH CHAT TOOL BY PI.SASHA  "
echo "#############################"
echo -ne "V. $VER\n\n"
printf '> '
read -n4 COMMND
while true;
do
case $COMMND in

msgs) #Standard message
echo -ne "\n***************\nMESSAGE:\n"
read MSG
osascript -e 'tell application "System Events" to display dialog "'"$MSG"'" buttons "OK" default button 1'
echo -ne "***************\n\n"
printf '> '
read -n4 COMMND
;;

msga) #Advanced message
echo -ne "\n***************\nMESSAGE:\n"
printf 'TITLE  > '
read TITLE
printf 'BUTTON > '
read BUTTON
echo "TEXT:"
read MSG
osascript -e 'tell application "System Events" to display dialog "'"$MSG"'" buttons "'"$BUTTON"'" default button 1 with title "'"$TITLE"'"'
echo -ne "***************\n\n"
printf '> '
read -n4 COMMND
;;

chts) #Standart chat
echo -ne "\n***************\nMESSAGE:\n"
read MSG
RSPNS=$(osascript -e 'Tell application "System Events" to display dialog "'"$MSG"'" default answer "Message" buttons "Respond" default button 1' -e 'text returned of result')
if [ -z "$RSPNS" ]; then
echo "USER CANCELLED"
else
echo -ne "---------------\nREACTION:\n$RSPNS\n***************\n\n"
fi
printf '> '
read -n4 COMMND
;;

chta) #Advanced chat
echo -ne "\n***************\nMESSAGE:\n"
printf 'TITLE    > '
read TITLE
printf 'BUTTON   > '
read BUTTON
printf 'DEF.ANSW > '
read DEFANSW
echo "TEXT:"
read MSG
RSPNS=$(osascript -e 'tell application "System Events" to display dialog "'"$MSG"'" default answer "'"$DEFANSW"'" buttons "'"$BUTTON"'" default button 1 with title "'"$TITLE"'"' -e 'text returned of result')
if [ -z "$RSPNS" ]; then
echo "USER CANCELLED"
else
echo -ne "---------------\nREACTION:\n$RSPNS\n***************\n\n"
fi
printf '> '
read -n4 COMMND
;;

spks) #Speak standard
echo -ne "\n***************\nMESSAGE:\n"
printf 'VOL.(0-7) > '
read -n1 VOL
echo -ne "\nTEXT:\n"
read MSG
osascript -e 'say "'"$MSG"'"'
osascript -e 'set volume "'"$VOL"'"'
echo -ne "***************\n\n"
printf '> '
read -n4 COMMND
;;

quit) #Quit
echo
exit 0
;;

help) #Help
echo -ne "\nCOMMANDS\n"
echo "***************"
echo "> msgs : Standard Message"
echo -ne "Allows you to send a message to the user.\n\n"
echo "> msga : Advanced Message"
echo -ne "Allows you to send a message to the user with a few extra options.\n\n"
echo "> chts : Standard Chat"
echo -ne "Allows you to send a message to the user which they can respond to.\n\n"
echo "> chta : Advanced Chat"
echo -ne "Allows you to send a message to the user which the can respond to with a few extra options.\n\n"
echo "> spks : Standart Speak"
echo -ne "Allows you to send a message to the user which will be read to him, it allows you to controll the volume of the computer aswell.\n\n"
sleep 1
printf '> '
read -n4 COMMND
;;

*) #Error
echo -ne "\nINVALID COMMAND\nTYPE "help" FOR HELP"
sleep 1
echo ""
printf '> '
read -n4 COMMND
;;

esac
done

Any suggestions on how I can improve the code?

\$\endgroup\$
4
\$\begingroup\$

Avoid echo -ne

Although you intend to use this script specifically on Mac OS X, as a general rule of thumb, it's good to avoid the various flags of echo, because they are not portable.

In some of your use cases the flags are completely unnecessary, for example instead of this:

echo -ne "V. $VER\n\n"

You could write like this to get the same effect:

echo "V. $VER"
echo

In other cases, it's better to use printf, for example here:

echo -ne "\n***************\nMESSAGE:\n"

Just replace with printf, the end result will be the same.

Use indentation

It's customary to indent code blocks that belong to a specific logical unit, for example the body of a loop, if conditions, longer case statements, like this:

while true; do
    case $COMMAND in
        msgs)
            read MSG
            osascript -e 'tell application "System Events" to display dialog "'"$MSG"'" buttons "OK" default button 1'
            printf "***************\n\n"
            printf '> '
            read -n4 COMMAND
            ;;

It makes the code more readable when you see its structure.

Decompose to functions

The case statements are fairly long. The script will become easier to read if you extract those statements to functions.

Naming

I don't enjoy nitpicking on names, but COMMND looks like a typo and it's annoying. I don't think it's worth saving one character.

\$\endgroup\$
  • \$\begingroup\$ Thank you for the feedback, this will be very helpful in future projects. I hadn't even thought about using functions instead of placing it all inside of case statements. And also, about the name, I think you are correct, it's made sense in my head, but it is more logical to just use COMMAND rather than COMMND. About the identation, I've written this using the vim - function in terminal, should I just use spaces or tabs? Or is there a program which will do this automatically for me? Thank you again. \$\endgroup\$ – insanikov Apr 30 '15 at 11:49
  • \$\begingroup\$ I use vim too ;-) You can setup vim to do the indentation for you automatically. For example when I press Enter after starting an if statement, it breaks the line and moves the cursor to the correct position. Google for it, or look around on vi.stackexchange.com. \$\endgroup\$ – janos Apr 30 '15 at 13:23
  • 1
    \$\begingroup\$ As for using spaces or tabs, it's debatable and there is no standard for this. I borrow standards from Python, using spaces instead of tabs. This has the benefit that the scripts will look exactly the same wherever you display them. By contrast, the width of tab characters depends on the viewing tool. One thing is clear though: you should use either spaces everywhere or tabs everywhere, and never a mix of both. \$\endgroup\$ – janos Apr 30 '15 at 13:26
2
\$\begingroup\$

First of all, why do you repeat read -n4 COMMND in every block? Just put it at the top of the loop.

Typically, chat applications are implemented either as "client-server" -- one machine is the "server" and listens for requests from clients then distributes them out, or as "peer-to-peer" -- each chatter sends messages to the other chatter(s), who are listening for it.

Your current architecture has you logging in to the server and executing commands (a bash script). The thing is, many of these commands could be executed on the current machine. The only things that need to be executed on the remote host are the commands to osascript / "System Events" (and the voice ones too).

And the neat thing is that ssh lets you do that.

The usual use of ssh is interactively: it gives you a shell on the remote host. But a batch file can also use ssh as a batch command: it connects to the remote host, runs a command, and returns the result.

So, with a little use of ssh, you could change this script so it runs on the local machine.

e.g. instead of

osascript -e 'tell application "System Events" to display dialog "'"$MSG"'" buttons "'"$BUTTON"'" default button 1 with title "'"$TITLE"'"'

you could write

ssh $USER@$HOST 'osascript -e "'"tell application "System Events" to display dialog ""'""$MSG""'"" buttons ""'""$BUTTON""'"" default button 1 with title ""'""$TITLE""'"""'"'

you'd just need to set those variables.

\$\endgroup\$
  • \$\begingroup\$ Thank you for the feedback, I hadn't thought about putting 'read -n4 COMMND' at the top of the loop, very sharp. And also thank you for explaining how to execute the code on a not-local machine. I will use this for the final product. Thanks again! \$\endgroup\$ – insanikov Apr 30 '15 at 11:46
  • \$\begingroup\$ Also, I forgot to mention, if the command produces output, it gets sent back across the network to become the output of the ssh. \$\endgroup\$ – Snowbody Apr 30 '15 at 13:18
  • \$\begingroup\$ Thank you! Just another question, when I try to use your method ' ssh $USER@$HOST 'osascript -e "'"tell application "System Events" to display dialog ""'""$MSG""'"" buttons ""'""$BUTTON""'"" default button 1 with title ""'""$TITLE""'"""'"' ' then I get an error ' 24:30: syntax error: Expected end of line but found plural class name. (-2741) ' and I have no idea what goes wrong, but that probably is just due to my lack of experience with coding. \$\endgroup\$ – insanikov Apr 30 '15 at 13:58
  • \$\begingroup\$ It's probably the quotes. I'm not familiar with the quoting convention being used here and I just guessed at it. The "plural class name" is probably the word "buttons"; that's not being parsed properly. \$\endgroup\$ – Snowbody Apr 30 '15 at 14:46
  • \$\begingroup\$ for some reason AppleScript simply doesn't seem to work in combination with SSH. Maybe this is on purpose, maybe I am still doing something wrong. \$\endgroup\$ – insanikov Apr 30 '15 at 17:27

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.