Bash脚本用户输入提示
Bash script user input prompt
我在使用已知的生成用户输入提示的方法时遇到问题:
read -p "Input something: " variabile
如果尝试使用箭头键,这会导致问题,它会为每个箭头键笔划回显 ANSI 代码
read -e -p "Input something: " variable
这修复了箭头键问题,但当达到终端的宽度时,文本输入不会在换行符上继续,而是在同一行上,覆盖(视觉上)现有输入
echo -n "Input something: "; read -e variable
这显然解决了之前描述的两个问题...直到我发现输入内容然后按退格键会覆盖提示,而且当输入较长时,从输入的第二个换行符开始,视觉覆盖再次出现。
那么有没有好的提示方式可以避免上述问题呢?
更新
重新检查后,我现在知道是什么导致了 read -e -p
的输入覆盖
我正在使用这些变量来突出显示阅读提示的文本:
highlight=$(echo -e "\e[1;97m")
clear=$(echo -e "\e[0m")
read -e -p "Input$highlight something$clear: " variable
这是我可以在 read
提示符中使突出显示工作的唯一方法(将转义序列分配给变量不起作用,我需要像以前一样回显它们)但它们似乎也导致输入覆盖问题。
shell 跟踪它认为 提示的时间,以便了解用户输入的开始和停止位置。不幸的是,当您在提示中打印颜色转义码时,您会抛出 Bash 的计数,因为它希望转义字符在终端中占据 space。
为避免这种情况,您只需要将所有颜色序列包裹在 \[
and \]
中,这告诉您 shell 封闭的字符是非打印字符,不应计算在内。
例如,您的 highlight
变量应该是:
highlight=$(echo -e "\[\e[1;97m\]")
就我个人而言,我使用 color
and pcolor
functions from my Prompt.gem 项目,它处理正确的转义并使您的命令更容易阅读:
read -e -p "Input $(pcolor DEFAULT BOLD)something$(pcolor): " variable
正如 dimo414 提到的,readline 认为提示比实际的要长。它在计算长度时计算终端转义序列中的每个字符。可以看到它认为转义序列有多长如下
echo ${#highlight}
在 bash PS1 提示中,用 "\["
和 "\]"
包围这样的转义序列指示 readline 在计算当前行长度时忽略之间的所有内容,但是这些不是 bash read
内置的正确转义。
read
的转义符是 $'[=16=]1'
和 $'[=17=]2'
,如 BashFAQ 中所述,但根据我的经验,您需要 -e
选项read
,还有。做你想做的事的蛮力方式是:
read -e -p "Input "$'[=11=]1'"${highlight}"$'[=11=]2'something$'[=11=]1'"${clear}"$'[=11=]2'": "
为了终端独立性,您应该使用 tput 而不是硬编码的转义序列。阅读 man 5 termcap
.
请参阅 my dotfiles 以获取优雅的 bash 函数来为您执行上面的 begin/end 引用。
我在使用已知的生成用户输入提示的方法时遇到问题:
read -p "Input something: " variabile
如果尝试使用箭头键,这会导致问题,它会为每个箭头键笔划回显 ANSI 代码
read -e -p "Input something: " variable
这修复了箭头键问题,但当达到终端的宽度时,文本输入不会在换行符上继续,而是在同一行上,覆盖(视觉上)现有输入
echo -n "Input something: "; read -e variable
这显然解决了之前描述的两个问题...直到我发现输入内容然后按退格键会覆盖提示,而且当输入较长时,从输入的第二个换行符开始,视觉覆盖再次出现。
那么有没有好的提示方式可以避免上述问题呢?
更新
重新检查后,我现在知道是什么导致了 read -e -p
的输入覆盖
我正在使用这些变量来突出显示阅读提示的文本:
highlight=$(echo -e "\e[1;97m")
clear=$(echo -e "\e[0m")
read -e -p "Input$highlight something$clear: " variable
这是我可以在 read
提示符中使突出显示工作的唯一方法(将转义序列分配给变量不起作用,我需要像以前一样回显它们)但它们似乎也导致输入覆盖问题。
shell 跟踪它认为 提示的时间,以便了解用户输入的开始和停止位置。不幸的是,当您在提示中打印颜色转义码时,您会抛出 Bash 的计数,因为它希望转义字符在终端中占据 space。
为避免这种情况,您只需要将所有颜色序列包裹在 \[
and \]
中,这告诉您 shell 封闭的字符是非打印字符,不应计算在内。
例如,您的 highlight
变量应该是:
highlight=$(echo -e "\[\e[1;97m\]")
就我个人而言,我使用 color
and pcolor
functions from my Prompt.gem 项目,它处理正确的转义并使您的命令更容易阅读:
read -e -p "Input $(pcolor DEFAULT BOLD)something$(pcolor): " variable
正如 dimo414 提到的,readline 认为提示比实际的要长。它在计算长度时计算终端转义序列中的每个字符。可以看到它认为转义序列有多长如下
echo ${#highlight}
在 bash PS1 提示中,用 "\["
和 "\]"
包围这样的转义序列指示 readline 在计算当前行长度时忽略之间的所有内容,但是这些不是 bash read
内置的正确转义。
read
的转义符是 $'[=16=]1'
和 $'[=17=]2'
,如 BashFAQ 中所述,但根据我的经验,您需要 -e
选项read
,还有。做你想做的事的蛮力方式是:
read -e -p "Input "$'[=11=]1'"${highlight}"$'[=11=]2'something$'[=11=]1'"${clear}"$'[=11=]2'": "
为了终端独立性,您应该使用 tput 而不是硬编码的转义序列。阅读 man 5 termcap
.
请参阅 my dotfiles 以获取优雅的 bash 函数来为您执行上面的 begin/end 引用。