Reputation: 799
I am having issues with my known methods of generating user input prompts:
read -p "Input something: " variabile
This causes issues if attempting to use the arrow keys, it echoes the ANSI code for each arrow key stroke
read -e -p "Input something: " variable
This fixes the arrow keys issue but when reaching the width of the terminal, text input doesn't continue on a newline but on the same line, overwriting (visually) the existing input
echo -n "Input something: "; read -e variable
This apparently fixes both formerly described issues... until I found that typing something then hitting backspace overwrites the prompt and also when the input is longer, from the second newline of input the visual overwriting manifests again.
So is there a good way of producing prompts without the above issues?
UPDATE
After re-checking, I now know what's causing the input overwrite for read -e -p
I am using these variables for highlighting text for the read prompt:
highlight=$(echo -e "\e[1;97m")
clear=$(echo -e "\e[0m")
read -e -p "Input$highlight something$clear: " variable
This is the only way I could make the highlighting work inside read
prompt (assigning escape sequences to the variables doesn't work, I need to echo them like I did) but they also seem to cause the input overwrite issue.
Upvotes: 4
Views: 1611
Reputation: 48824
The shell keeps track of how long it thinks the prompt is, in order to know where the user's input starts and stops. Unfortunately when you print color escape codes in a prompt you throw of Bash's counting, since it expects the escape characters to take up space in the terminal.
To avoid that, you just need to wrap all color sequences in \[
and \]
, which tells your shell the enclosed characters are non-printing, and should not be counted.
For example, your highlight
variable should be:
highlight=$(echo -e "\[\e[1;97m\]")
Personally, I use the color
and pcolor
functions from my Prompt.gem project, which handles the proper escaping and would make your command much easier to read:
read -e -p "Input $(pcolor DEFAULT BOLD)something$(pcolor): " variable
Upvotes: 1
Reputation: 752
As dimo414 mentions, readline thinks the prompt is longer than it is. It counts every character in the terminal escape sequence in computing the length. You can see how long it thinks the escape sequence is as follows
echo ${#highlight}
In the bash PS1 prompt, surrounding such an escape sequence with "\["
and "\]"
instructs readline to ignore everything between when calculating current line length, but these are not the right escapes for the bash read
built-in.
The escapes for read
are $'\001'
and $'\002'
, as mentioned in BashFAQ, but in my experience, you need the -e
option on read
, as well. The brute force way to do what you want would be:
read -e -p "Input "$'\001'"${highlight}"$'\002'something$'\001'"${clear}"$'\002'": "
You should use tput rather than hard-coded escape sequences, for the sake of terminal independence. Read man 5 termcap
.
See my dotfiles for elegant bash functions to do the begin/end quoting above for you.
Upvotes: 1