bash 脚本中的交互式多项选择

bash 脚本中的交互式多项选择

有没有一种简单的方法可以让用户交互式地选择 的输出行
之一lsblk -f

NAME    FSTYPE LABEL        MOUNTPOINT
sda                         
├─sda1  ntfs   WINRE_DRV    
├─sda2  vfat   SYSTEM_DRV   
├─sda3  vfat   LRS_ESP      
├─sda4                      
├─sda5  ntfs   Windows8_OS  /media/Win8
├─sda6  ntfs   Data        /media/Data
├─sda7  ext4   linux        /
├─sda8                      
├─sda9  ntfs   4gb-original 
├─sda10 ntfs   PBR_DRV      
└─sda11 ext4   home         /home

并让所选行填充到变量中以便在脚本的继续中使用?

我认为如果用户可以使用箭头键在各行中上下移动并按 Enter 键选择一个,那就完美了。 (我想我之前在安装过程中的一些配置脚本中已经看到过这一点。)如果这不可能,至少我如何在每行前面获取数字以让用户选择使用read

答案1

您正在寻找dialog。它是一个非常强大的工具,用于ncurses提供很多选项。我建议您仔细阅读它的联机帮助页。具体来说,您需要以下--menu选项:

   --menu text height width menu-height [ tag item ] ...
          As its name suggests, a menu box is a dialog  box  that  can  be
          used  to present a list of choices in the form of a menu for the
          user to choose.  Choices are displayed in the order given.  Each
          menu entry consists of a tag string and an item string.  The tag
          gives the entry a name to distinguish it from the other  entries
          in the menu.  The item is a short description of the option that
          the entry represents.  The user can move between  the  menu  en‐
          tries  by  pressing the cursor keys, the first letter of the tag
          as a hot-key, or the number keys 1-9. There are menu-height  en‐
          tries  displayed  in  the menu at one time, but the menu will be
          scrolled if there are more entries than that.

          On exit the tag of the chosen menu entry will be printed on dia‐
          log's  output.  If the "--help-button" option is given, the cor‐
          responding help text will be printed if  the  user  selects  the
          help button.

不幸的是,由于各种引用问题,使用包含空格的命令的输出以合理的方式实现它是相当复杂的。无论如何,我没能做到这一点,不得不求助于使用eval.尽管如此,它确实有效并且满足了您的要求:

#!/usr/bin/env bash
tmp=$(mktemp)
IFS=
eval dialog --menu \"Please choose a filesystem:\" 50 50 10 $(lsblk -f | sed -r 's/^/"/;s/$/" " "/' | tr $'\n' ' ') 2>$tmp
D=$(tr -d '│├└─' < $tmp | sed 's/^[ \t]*//' | cut -d' ' -f1)
printf "You chose:\n%s\n" "$D"

要获得更便携的方法,请将grep命令更改为

justsed格式化输出,lsblk以便每个输出行周围都有引号(即对话框的“标签”),后跟带引号的空格(即对话框的“项目”),并tr用空格和树部分字符替换换行符。

结果如下:

              ┌────────────────────────────────────────────────┐
              │ Please choose a filesystem:                    │  
              │ ┌────────────────────────────────────────────┐ │  
              │ │     NAME   FSTYPE LABEL MOUNTPOINT         │ │  
              │ │     sda                                    │ │  
              │ │     ├─sda1                                 │ │  
              │ │     ├─sda2                                 │ │  
              │ │     ├─sda3              /winblows          │ │  
              │ │     ├─sda4                                 │ │  
              │ │     ├─sda5                                 │ │  
              │ │     ├─sda6              /home              │ │  
              │ │     ├─sda7              /                  │ │  
              │ │     └─sda8              [SWAP]             │ │  
              │ └────↓(+)────────────────────────────90%─────┘ │  
              │                                                │  
              ├────────────────────────────────────────────────┤  
              │           <  OK  >      <Cancel>               │  
              └────────────────────────────────────────────────┘  

答案2

在正常操作下,您无法更改光标上方的行——它们已经被刷新了。您可能看到的脚本可能使用了curses库,所以如果您真的想要这个,我建议使用像python这样的脚本语言并在那里使用curses库。

将数字放在每行前面要容易得多。您可以使用此 awk 行将数字放在它们前面。可能有一种更优雅的方法,但这可行。更改正则表达式以满足您的需求。

lsblk -f | awk 'BEGIN{disk=1;} /sd[a-z][1-9]+/ {print disk, ": ",$RT;disk=disk+1;next}{print "   ", $RT}'

相关内容