在bash中选择菜单

时间:2014-07-13 20:57:49

标签: bash menu formatting

出于某种原因,我的菜单呈现如下:

1) RUNTHROUGH         6) option 4
2) QUIT               7) option leg
3) NEW SEARCH PATERN    8) option arm
4) CLEAR SEARCHES             9) option whatever
5) option 1                          10) option blabla

,但我希望它能够正确对齐,如下所示:

1) RUNTHROUGH         6) option 4
2) QUIT               7) option leg
3) NEW SEARCH PATERN  8) option arm
4) CLEAR SEARCHES     9) option whatever
5) option 1          10) option blabla

我该怎么做?

我从两个数组中填充菜单:

一个是由像这样的标签变量构建的:

MENU_OPTIONS=( "$SCRIPT_RUNTHROUGH" "$PROGRAM_QUIT" "$PATTERN_NEW" "$PATTERN_CLEAR" )

其中变量具有这样的值,带有颜色转义

SCRIPT_RUNTHROUGH=$'\e[1;31mRUNTHROUGH\e[0;33m'
PROGRAM_QUIT=$'\e[1;31mQUIT\e[0;33m'
PATTERN_NEW=$'\e[1;31mNEW SEARCH PATERN\e[0;33m'
PATTERN_CLEAR=$'\e[1;31mCLEAR SEARCHES\e[0;33m'

另一个数组entries来自file:

readarray -t entries < ./file

file的内容是原始文本数据:

option 1
option 4
option leg
option arm
option whatever
option blabla

所以select块就像:

select opt in "${MENU_OPTIONS[@]}" "${entries[@]}";
do
    case "$opt" in
        ...)
        ;;

1 个答案:

答案 0 :(得分:3)

Bash主要计算每个选项中的char,无论它们是&#34;可显示&#34;或不。因此,用于突出显示某些项目的转义代码会错误显示。

以下是一个例子:

sh$ for i in {1..12}; do OPTIONS[$i]=$(printf "option-%02d" $i); done
sh$ select i in "${OPTIONS[@]}"; do echo $i ; done
1) option-01    4) option-04   7) option-07  10) option-10
2) option-02    5) option-05   8) option-08  11) option-11
3) option-03    6) option-06   9) option-09  12) option-12

这是预期的。但如果我突出第4项:

sh$ OPTIONS[4]=$'\e[1;31moption-04\e[0;33m'
sh$ select i in "${OPTIONS[@]}"; do echo $i ; done
1) option-01    4) option-04           7) option-07  10) option-10
2) option-02    5) option-05   8) option-08  11) option-11
3) option-03    6) option-06   9) option-09  12) option-12

解决方法

嗯......它更像是一种破解而不是一种解决方法。真。

我在每个选项的末尾添加一些额外的空格以扩大列。相反,我在突出显示的选项的末尾添加了一些\b(6在我的测试中给出了很好的结果)。我不能更精确,因为我无法清楚地确定要遵循的规则。您可能必须准备好进行反复试验...
(事情更复杂的事实Bash使用标签的混合空格缩进各种选项)

无论如何,这在我的系统上正确显示:

sh$ for i in {1..12}; do OPTIONS[$i]=$(printf "option-%02d        " $i); done
#                                                         ^^^^^^^^
sh$ OPTIONS[4]=$'\e[1;31moption-04\e[0;33m\b\b\b\b\b\b'
#                                         ^^^^^^^^^^^^
sh$ select i in "${OPTIONS[@]}"; do echo $i ; done
1) option-01            5) option-05           9) option-09        
2) option-02            6) option-06          10) option-10        
3) option-03            7) option-07          11) option-11        
4) option-04            8) option-08          12) option-12 

编辑:我对我的例子中的事实感到困惑,菜单被8个字符关闭了。与各种转义码中的 bytes 的数量不匹配。

但是,考虑到GNU bash 4.2中的代码: (execute_cmd.c

static int
displen (s)
     const char *s;
{
#if defined (HANDLE_MULTIBYTE)
  wchar_t *wcstr;
  size_t wclen, slen;

  wcstr = 0;
  slen = mbstowcs (wcstr, s, 0);
  if (slen == -1)
    slen = 0;
  wcstr = (wchar_t *)xmalloc (sizeof (wchar_t) * (slen + 1));
  mbstowcs (wcstr, s, slen + 1);
  wclen = wcswidth (wcstr, slen);
  free (wcstr);
  return ((int)wclen);
#else
  return (STRLEN (s));
#endif
}

如果使用多字节支持编译Bash,它会使用mbstowcs转换原始字符串,以便使用wcswidth计算其长度。鉴于我的系统有UTF-8 LC_CTYPE,可能mbstowcs将转义代码错误转换为某些Unicode字符...