Escolha múltipla interativa em um script bash

2

Existe uma maneira simples de permitir que o usuário escolha interativamente uma das linhas do saída de 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

E deixe a linha escolhida ser preenchida em uma variável para usar na continuação do script?

Achei que seria perfeito se o usuário pudesse usar as teclas de seta para subir e descer as linhas e pressionar Enter para selecionar uma. (Acho que já vi isso antes em alguns scripts de configuração durante a instalação.) Se isso não for possível, pelo menos como conseguir números na frente de cada linha para permitir que o usuário escolha usando read ?

    
por rubo77 26.09.2014 / 03:31

2 respostas

2

Você está procurando dialog . É uma ferramenta muito poderosa e usa ncurses para fornecer muitas opções. Eu sugiro que você leia sua manpage. Especificamente, você quer a opção --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.

Infelizmente, implementá-lo de maneira sã usando a saída de um comando que contém espaços é bastante complexo devido a vários problemas de cotação. De qualquer forma, eu não consegui fazer isso, e tive que recorrer ao uso de eval . No entanto, funciona e faz o que você pediu:

#!/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"

Para uma abordagem mais portátil, altere o comando grep para

O sed apenas formata a saída de lsblk para que haja cotações em torno de cada linha de saída (a "tag" do diálogo), seguida por um espaço entre aspas (o "item" da caixa de diálogo) e tr substitui novas linhas com espaços e os caracteres das partes da árvore.

O resultado é assim:

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

Em operação normal, não é possível alterar as linhas acima do cursor - elas já foram liberadas. O script que você provavelmente viu provavelmente estava usando a biblioteca curses, então se você realmente quer isso eu recomendo usar uma linguagem de script como python e usar a biblioteca curses lá.

Colocar números na frente de cada linha é muito mais fácil. Você pode usar essa linha de awk para colocar números na frente deles. Há provavelmente uma maneira mais elegante, mas isso funciona. Altere o regex para atender às suas necessidades.

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