Saltar al contenido

Menú de selección múltiple en script bash

Solución:

Solución 1:

Creo que deberías echarle un vistazo al diálogo o al látigo.

caja de diálogo

Editar:

Aquí hay un script de ejemplo que usa las opciones de su pregunta:

#!/bin/bash
cmd=(dialog --separate-output --checklist "Select options:" 22 76 16)
options=(1 "Option 1" off    # any option can be set to default to "on"
         2 "Option 2" off
         3 "Option 3" off
         4 "Option 4" off)
choices=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty)
clear
for choice in $choices
do
    case $choice in
        1)
            echo "First Option"
            ;;
        2)
            echo "Second Option"
            ;;
        3)
            echo "Third Option"
            ;;
        4)
            echo "Fourth Option"
            ;;
    esac
done

Solucion 2:

Si usted piensa whiptail es complejo, aquí va un código de solo bash que no exactamente Lo que quieras. Es corto (~ 20 líneas), pero un poco críptico para un principiante. Además de mostrar “+” para las opciones marcadas, también proporciona comentarios para cada acción del usuario (“opción no válida”, “opción X marcada” / desmarcada, etc.).

Dicho esto, ¡ahí lo tienes!

Espero que lo disfrutes … fue un desafío bastante divertido hacerlo 🙂

#!/bin/bash

# customize with your own.
options=("AAA" "BBB" "CCC" "DDD")

menu() {
    echo "Avaliable options:"
    for i in ${!options[@]}; do 
        printf "%3d%s) %sn" $((i+1)) "${choices[i]:- }" "${options[i]}"
    done
    if [[ "$msg" ]]; then echo "$msg"; fi
}

prompt="Check an option (again to uncheck, ENTER when done): "
while menu && read -rp "$prompt" num && [[ "$num" ]]; do
    [[ "$num" != *[![:digit:]]* ]] &&
    (( num > 0 && num <= ${#options[@]} )) ||
    { msg="Invalid option: $num"; continue; }
    ((num--)); msg="${options[num]} was ${choices[num]:+un}checked"
    [[ "${choices[num]}" ]] && choices[num]="" || choices[num]="+"
done

printf "You selected"; msg=" nothing"
for i in ${!options[@]}; do 
    [[ "${choices[i]}" ]] && { printf " %s" "${options[i]}"; msg=""; }
done
echo "$msg"

Solución 3:

Esta es una forma de hacer exactamente lo que desea utilizando solo funciones de Bash sin dependencias externas. Marca las selecciones actuales y le permite alternarlas.

#!/bin/bash
# Purpose: Demonstrate usage of select and case with toggleable flags to indicate choices
# 2013-05-10 - Dennis Williamson

choice () {
    local choice=$1
    if [[ ${opts[choice]} ]] # toggle
    then
        opts[choice]=
    else
        opts[choice]=+
    fi
}

PS3='Please enter your choice: '
while :
do
    clear
    options=("Option 1 ${opts[1]}" "Option 2 ${opts[2]}" "Option 3 ${opts[3]}" "Done")
    select opt in "${options[@]}"
    do
        case $opt in
            "Option 1 ${opts[1]}")
                choice 1
                break
                ;;
            "Option 2 ${opts[2]}")
                choice 2
                break
                ;;
            "Option 3 ${opts[3]}")
                choice 3
                break
                ;;
            "Option 4 ${opts[4]}")
                choice 4
                break
                ;;
            "Done")
                break 2
                ;;
            *) printf '%sn' 'invalid option';;
        esac
    done
done

printf '%sn' 'Options chosen:'
for opt in "${!opts[@]}"
do
    if [[ ${opts[opt]} ]]
    then
        printf '%sn' "Option $opt"
    fi
done

Para ksh, cambie las dos primeras líneas de la función:

function choice {
    typeset choice=$1

y el tinglado a #!/bin/ksh.


Solución 4:

Escribí una biblioteca llamada cuestionario, que es un mini-DSL para crear cuestionarios de línea de comandos. Solicita al usuario que responda una serie de preguntas e imprime las respuestas en stdout.

Hace que su tarea sea realmente fácil. Instalarlo con pip install questionnaire y crea un guión, p. ej. questions.py, como esto:

from questionnaire import Questionnaire
q = Questionnaire(out_type="plain")

q.add_question('options', prompt="Choose some options", prompter="multiple",
               options=['Option 1', 'Option 2', 'Option 3', 'Option 4'], all=None)

q.run()

Entonces corre python questions.py. Cuando haya terminado de responder a las preguntas, se imprimirán en formato estándar. Funciona con Python 2 y 3, uno de los cuales es casi seguro que esté instalado en su sistema.

También puede manejar cuestionarios mucho más complicados, en caso de que alguien quiera hacer esto. A continuación se muestran algunas características:

  • Imprime las respuestas como JSON (o como texto sin formato) en stdout
  • Permite a los usuarios retroceder y volver a responder preguntas.
  • Admite preguntas condicionales (las preguntas pueden depender de respuestas anteriores)
  • Admite los siguientes tipos de preguntas: entrada sin procesar, elija una, elija muchas
  • Sin acoplamiento obligatorio entre la presentación de preguntas y los valores de respuesta

Solución 5:

Aquí hay una función bash que permite al usuario seleccionar múltiples opciones con las teclas de flecha y la barra espaciadora, y confirmar con Enter. Tiene una agradable sensación de menú. Lo escribí con la ayuda de https://unix.stackexchange.com/a/415155. Se puede llamar así:

multiselect result "Option 1;Option 2;Option 3" "true;;true"

El resultado se almacena como una matriz en una variable con el nombre proporcionado como primer argumento. El último argumento es opcional y se utiliza para seleccionar algunas opciones de forma predeterminada. Se parece a esto.

function prompt_for_multiselect {

    # little helpers for terminal print control and key input
    ESC=$( printf "33")
    cursor_blink_on()   { printf "$ESC[?25h"; }
    cursor_blink_off()  { printf "$ESC[?25l"; }
    cursor_to()         { printf "$ESC[$1;${2:-1}H"; }
    print_inactive()    { printf "$2   $1 "; }
    print_active()      { printf "$2  $ESC[7m $1 $ESC[27m"; }
    get_cursor_row()    { IFS=';' read -sdR -p $'E[6n' ROW COL; echo ${ROW#*[}; }
    key_input()         {
      local key
      IFS= read -rsn1 key 2>/dev/null >&2
      if [[ $key = ""      ]]; then echo enter; fi;
      if [[ $key = $'x20' ]]; then echo space; fi;
      if [[ $key = $'x1b' ]]; then
        read -rsn2 key
        if [[ $key = [A ]]; then echo up;    fi;
        if [[ $key = [B ]]; then echo down;  fi;
      fi 
    }
    toggle_option()    {
      local arr_name=$1
      eval "local arr=("${${arr_name}[@]}")"
      local option=$2
      if [[ ${arr[option]} == true ]]; then
        arr[option]=
      else
        arr[option]=true
      fi
      eval $arr_name="("${arr[@]}")"
    }

    local retval=$1
    local options
    local defaults

    IFS=';' read -r -a options <<< "$2"
    if [[ -z $3 ]]; then
      defaults=()
    else
      IFS=';' read -r -a defaults <<< "$3"
    fi
    local selected=()

    for ((i=0; i<${#options[@]}; i++)); do
      selected+=("${defaults[i]}")
      printf "n"
    done

    # determine current screen position for overwriting the options
    local lastrow=`get_cursor_row`
    local startrow=$(($lastrow - ${#options[@]}))

    # ensure cursor and input echoing back on upon a ctrl+c during read -s
    trap "cursor_blink_on; stty echo; printf 'n'; exit" 2
    cursor_blink_off

    local active=0
    while true; do
        # print options by overwriting the last lines
        local idx=0
        for option in "${options[@]}"; do
            local prefix="[ ]"
            if [[ ${selected[idx]} == true ]]; then
              prefix="[x]"
            fi

            cursor_to $(($startrow + $idx))
            if [ $idx -eq $active ]; then
                print_active "$option" "$prefix"
            else
                print_inactive "$option" "$prefix"
            fi
            ((idx++))
        done

        # user key control
        case `key_input` in
            space)  toggle_option selected $active;;
            enter)  break;;
            up)     ((active--));
                    if [ $active -lt 0 ]; then active=$((${#options[@]} - 1)); fi;;
            down)   ((active++));
                    if [ $active -ge ${#options[@]} ]; then active=0; fi;;
        esac
    done

    # cursor position back to normal
    cursor_to $lastrow
    printf "n"
    cursor_blink_on

    eval $retval="("${selected[@]}")"
}
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *