1

I have written a shell script for automating some tasks that I run from the terminal as -

v@ubuntu:$ ./automate.sh from:a1 to:a2 msg:'edited'

How can I (if at all) customize the script so as to enter each argument in a custom format on a separate line and execute it by pressing some other key to execute the shell script? So, I would do -

v@ubuntu:$ ./automate.sh
from : a1
to : a2
msg : 'next change'

... and then hit say Ctrl+Enter or F5 to execute this particular script?

NOTE : I know there is a hacky work around by simply typing ./automate.sh \ and hitting Enter after the trailing backslash to get a new line, but I was hoping to find a more elegant way to do this from within the script itself. Also, I've purposely changed each argument to include whitespaces and the msg argument to include a string with spaces. So if anyone can point me in the right direction as to how to accomplish that as an added bonus, I'll be really grateful :)

fwx
  • 333
  • 1
  • 5
  • 14
  • I suggest to use a [here document](https://en.wikipedia.org/wiki/Here_document) and parse stdin in your script or use double quotes. – Cyrus Mar 18 '16 at 06:07
  • Sorry I took so long. Was never logged in on my work machine. – fwx Apr 13 '16 at 16:54

2 Answers2

1

If you know the number of arguments it is easy. Basics first.

#!/bin/bash

if [ $# == 0 ] 
then
    read v1    # gets onto new line. reads the whole line until ENTER
    read v2    # same
    read v3    # same
fi
# Parse $v1, $v2, $v3 as needed and run your script
echo ""
echo "Got |$v1|, |$v2|, |$v3|"

When you type automate.sh and hit enter the script is started, having received no arguments. With no arguments ($# == 0) the first read is executed, which prints a new line, waits, and gets the line typed in (once enter is hit) into $v1. The control goes back to the script, the next read gets the next typed line ... after the last one it drops out of if-else and continues. Parse your variables and run the script.

Session:

> automate.sh  Enter
typed line     Enter
more items     Enter
yet more       Enter

Got |typed line| |more items| |yet more|
>

You don't need Control-Enter or F5, it continues after 3 (three) lines.

This also allows you to provide both behaviors. Add an else, which will be executed if there are some arguments. You can then use the script by either supplying arguments on the first line (invocation you have so far), or in this new way.

If you need an unspecified number of arguments this approach will need more work.


Read words in input line into variables

If read is followed by variable names, like read v1 v2, then it reads each word into a variable, and the last variable gets everything that may have remained on the line. So replace read lines with

read k1 p1 s1 
read k2 p2 s2
read k3 p3 s3

Now $k1 contains the first word (from), and $k2 and $k3 have the first words on their lines; then $p1 (etc) have the second word (:), and $s1 (etc) have everything else to the end of their lines (a1, a2, 'next change'). So you don't need those single quotes. All this is simple to modify if you want the script to print something on each line before input.

Based on the clarification in the comment, it is indeed desirable to not have to enter the whole strings, as one might think. This is "simple to modify"

read -p 'from :' s1
read -p 'to :'   s2
read -p 'msg :'  s3

Now the user only needs to enter the part after :, captured in $s variables. All else is the same.


See, for example: The section on user input in the Bash Guide; Their Advanced Guide (special variables); For a far more involved user interaction, this post. And, of course, man read.

Community
  • 1
  • 1
zdim
  • 64,580
  • 5
  • 52
  • 81
  • +1 for the links and an exhaustive explanation. i'd just like to suggest that using `read -p 'From : ' v1` in the loop you mention, worked out much more elegantly for me. thanks a lot! – fwx Mar 18 '16 at 15:40
  • @user1649740 Glad it helped :). I wanted to stick to what you requested, that all of that be entered. I did think that it would be nicer to only enter what is after `:`, which is why I have the statement "_...simple to modify if you want the script to print something..._". I am adding that to the solution, for the benefit of others who may come. – zdim Mar 18 '16 at 17:02
1

It will be hard to bind Control-Enter in bash. If you are ok to change it for Control-D then everything might look like:

#!/usr/local/bin/bash

read -p 'From: ' from
read -p 'To: ' to
read -p 'Msg: ' msg

read keystroke

if [ "$keystroke" == "^D" ]; then
   echo "$from $to $msg"
   # do something else 
fi
sotona
  • 1,731
  • 2
  • 24
  • 34
  • I really like the flow of this. But unfortunately, when I run it, the echo line does not print anything. Tried changing the keystroke value as well. Any idea what might be going wrong? – fwx Mar 18 '16 at 08:41
  • I actually just got rid of the keystroke check. Turns out if I just continue and press enter after I'm done, everything works out. I asked about the separate keystroke to execute option because I thought that with arguments on new lines, the enter key might get assigned to something else. Thanks a lot for your help! – fwx Mar 18 '16 at 08:55