BASH Shell script - help with read

Hi all,

I'm sure this is quite a simple problem, but i'm completely new to shell scripting, so bare with me. Having problems with the read command. Here's what I have:

read -rp "Command to execute: " the_command
...
...
echo "$the_command"
...
...
eval "$the_command"

Now, say, for instance the user enters the command to execute as echo "this is a test" - all works fine... the echo shows the correct command and the eval executes the command, echoing "this is a test".

BUT... if the user enters the command as echo "this id a typeo" - they go back to correct the mistake so that it now reads echo "this is a typeo" - now the script errors. The echo shows the correct command, but the eval has a problem. Is it possible that the variable the_command is getting every keystroke (including backspaces) and not just the final string? Can someone please help out a newbie :slight_smile:

Cheers,
Justin

Please copy and paste your script on here with code tags. What you posted works fine on my Solaris machine.

#!/bin/sh
read -rp "Command to execute: " the_command
echo "$the_command"
eval "$the_command"

Here's what happens:

but now i enter the command as echo "cat" but realise it's supposed to be echo "ratty" so i use the left cursor and backspace to fix the typeo;

Eventually the script will be used to enter commands such as:
shake "c:\test\test.#.tiff" -t 1-100

The reason i need this to work is because I anticipate users will drag a file into the terminal to get the filepath, but will need to change the resulting filepath from "c:\test\test.tiff" to "c:\test\test.#.tiff" for the script to execute.

p.s. I should mention that i'm running the script through Cygwin on a Windows machine.

Does the script have to be run by sh? Have you tried running it with ksh or bash?

More generic version. Echo is echo and read is read.

echo -e "C.. execute:\c"
read the_command
# or read -r  # what you need ?  I think that editionkeys handling in read depends which shell you use. Why to use -r in this case ?
echo "$the_command"
$the_command
eval "$the_command"

Try using backspace instead of the left cursor key.

When I run it on Cygwin, it does not crash. However, it does not process correctly due to the codes generated by the left cursor key and I get the following:

./test.sh: line 4: $'cat\E[D\E[D\E[Dratty': command not found

Firstly, thanks for the replies, guys.. i appreciate the help.

ilikecows: yes, changed it to #!/bin/bash but makes no difference.

kshji: I need to use the read -r option so that it interprets the "\" in inputted filepaths correctly.

mrtiller: If I just use backspace, you're right, it works.... However, I'm assuming the users of the script will not necessarily use backspace only and might do as I described and use the arrow keys and backspace - in which case I don't want the script to go funny on me.

I think you're right - it's not processing correctly due to the codes generated by the left cursor and going over the top of what was already there... is there any way I can tell it to ignore those keystrokes and just store the final string, no matter how it is created?

Cheers all,
Justin

The following will process the back arrow keys by removing the codes for these keys plus removing the previous character (since the codes are indicating this character should be deleted):

#!/bin/sh
read -rp "Command to execute: " the_command
while [ "`expr $the_command : '.*\(\[\).*'`" != "" ]
do
        echo "looping" >&2
        the_command=`echo $the_command | sed 's/.^[\[D//'`
done
echo "*$the_command*"
eval "$the_command"

The combination ^[ shown should actually be entered as an escape character. Notice we need a while loop - the /g switch will not work (at least not that I can see).

The problem with this is that it is specific to back arrow keys. If the person presses some other keys and tries to erase them with back arrow, this code may fail. The general problem of line editing can be messy.

Another approach would be to present the user with numbered menu items and check which menu item was selected. This would prevent mistyping the name of a program. The menu could be static or could even be generated dynamically by the shell script.

tested cygwin ksh

while true
do
        echo -n "filename:"
        read  -r str
        # remove cursor keys
        some=${str//$'\x1b'[D/}
        some=${some//$'\x1b'[A/}
        some=${some//$'\x1b'[C/}
        some=${some//$'\x1b'[B/}
        [ "$str" != "$some" ] && echo "don't use array keys, only backspace" && continue
        break
done
#now str is okay
echo "$str"

Why read again ? = Wysewyg is not correct if data include cursor keys = not same what user has tried.

This enough in cygwin, but in generic version you need to read cursorkeys value using tput and remove those values.