Клавиша со стрелкой / меню Enter

Я делаю что-то подобное тому, в чем OP, кажется, нуждается. У меня есть альпийская проверка, чтобы видеть, использую ли я ее локально или удаленно через экран. Если это удаленно, я использую экран для открытия сценария, который называет elinks, и если это локально (т.е. что-либо еще), я использую Firefox для открытия URL.

В .pinerc:

url-viewers=_TEST("test '${TERM}' = screen-bce")_ "/usr/bin/screen screlinks _URL_", "/usr/bin/firefox _URL_"

Сценарий, который я называю проверками "screlinks", если там уже выполнение elinks и раз так использует - удаленная опция открыть новую вкладку.

running='elinks -remote ping()'
if $running
then # echo "elinks running"
  /usr/bin/elinks -remote $@
else # echo "elinks not running"
  /usr/bin/elinks $@
fi

Конечный результат состоит в том, что, когда я использую альпийский на экране и я открываю URL, я получаю новый экранный процесс, который выполняет elinks. Я могу переключить там использование соответствующей команды ^A и закрыть его, когда я сделан или оставляю его, открывают и добавляют дополнительные URL как вкладки.

10
18.11.2018, 08:25
2 ответа

dialog - отличный инструмент для того, что вы пытаетесь достичь. Вот пример простого меню из 3-х вариантов:

dialog --menu "Choose one:" 10 30 3 \
    1 Red \
    2 Green \
    3 Blue

Синтаксис:

dialog --menu <text> <height> <width> <menu-height> [<tag><item>]

Выбор будет отправлен в stderr. Вот пример скрипта, использующего 3 цвета.

#!/bin/bash
TMPFILE=$(mktemp)

dialog --menu "Choose one:" 10 30 3 \
    1 Red \
    2 Green \
    3 Blue 2>$TMPFILE

RESULT=$(cat $TMPFILE)

case $RESULT in
    1) echo "Red";;
    2) echo "Green";;
    3) echo "Blue";;
    *) echo "Unknown color";;
esac

rm $TMPFILE

В Debian вы можете установить dialog через одноимённый пакет.

.
7
27.01.2020, 20:00

Я искал этого короля информации. Было здорово найти его здесь.

Итак, я пользуюсь случаем, чтобы повторно -использовать то, что я видел здесь, и улучшить его, (надеюсь ).

Одно ограничение в меню было связано, например, с ограничением количества элементов, связанных с терминалом.

Итак,Я изменил исходный скрипт, но добавил некоторые функции:

  • Многоколоночное меню (для увеличения количества элементов для выбора)
  • Меню множественного выбора (для улучшения некоторых функций, таких как «выбор всех/ничего»

Я делюсь им здесь в файлах сценария :один с измененным меню и один соответствующий с примером использования. Поскольку у меня возникли проблемы со ссылкой на версию bash (, версию < 4.3 и версию >= 4.3 ), вы также найдете две версии скриптов, которые работают на обоих уровнях версии bash.

menu.sh:

#!/bin/bash 
#####################################################################################################################
#
#           R5: MAJ 22/11/2021 : EML 
#               - Pb d'affichage du menu sur on dépasse la taille de l'écran
#               - On restreint le choix au 40 derniers fichiers
#           R6: MAJ 23/11/2021 : EML 
#               - On détermine automatiquement la taille de l'écran pour vérifier que l'affichage est Ok
#               - On affichera le menu compatible du coup
#               - Ajout des flèche gauche/droite pour une évolution sur un menu à plusieurs colonnes parametrables
#           R7: MAJ 24/11/2021 : EML 
#               - Correction pour support toute version de bash
#               - version < 4.3 : option "local -n" inconnue ==> fonction xxx_43m
#               - version > 4.3 : option "local -n" reconnue ==> fonction xxx_43p
#               - Possibilité de délectionner tout ou rien
#           R8: MAJ 24/11/2021 : EML 
#               - Correction checkwinsize
#               - Correction positionnement sur la fenetre
#
#
# SOURCES :
#   https://www.it-swarm-fr.com/fr/bash/menu-de-selection-multiple-dans-le-script-bash/958779139/ 
#   https://unix.stackexchange.com/questions/146570/arrow-key-enter-menu/415155#415155
#
#####################################################################################################################
export noir='\e[0;30m'
export gris='\e[1;30m'
export rougefonce='\e[1;31m'
export rouge='\e[0;31m'
export rose='\e[1;31m'
export vertfonce='\e[0;32m'
export vertclair='\e[1;32m'
export orange='\e[0;33m'
export jaune='\e[1;33m'
export bleufonce='\e[0;34m'
export bleuclair='\e[1;34m'
export violetfonce='\e[0;35m'
export violetclair='\e[1;35m'
export cyanfonce='\e[0;36m'
export cyanclair='\e[1;36m'
export grisclair='\e[0;37m'
export blanc='\e[1;37m'
export neutre='\e[0;m'

function checkwinsize {
    local __items=$1
    local __lines=$2
#local __err=$3

    if [ $__items -ge $__lines ]; then
#       echo "La taille de votre fenêtre ne permet d'afficher le menu correctement..."
        return 1
    else
#       echo "La taille de votre fenêtre est de $__lines lignes, compatible avec le menu de $__items items..."
        return 0
    fi
} 
function multiselect_43p {
    # little helpers for terminal print control and key input
    ESC=$( printf "\033")
    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#*[}; }
    get_cursor_col()    { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${COL#*[}; }

    local return_value=$1
    local colmax=$2
    local offset=$3
    local -n options=$4
    local -n defaults=$5
    local title=$6
    local LINES=$( tput lines )
    local COLS=$( tput cols )

    clear

#   checkwinsize $(( ${#options[@]}/$colmax )) $LINES
    err=`checkwinsize $(( ${#options[@]}/$colmax )) $(( $LINES - 2)); echo $?`

    if [[ ! $err == 0 ]]; then
        echo "La taille de votre fenêtre est de $LINES lignes, incompatible avec le menu de ${#_liste[@]} items..."
            cursor_to $lastrow
        exit
    fi 

    local selected=()
    for ((i=0; i<${#options[@]}; i++)); do
        if [[ ${defaults[i]} = "true" ]]; then
            selected+=("true")
        else
            selected+=("false")
        fi
        printf "\n"
    done

    cursor_to $(( $LINES - 2 ))
    printf "_%.s" $(seq $COLS)
    echo -e "$bleuclair / $title / | $vertfonce select : key [space] | (un)select all : key ([n])[a] | move : arrow up/down/left/right or keys k/j/l/h | validation : [enter] $neutre\n" | column  -t -s '|'

    # determine current screen position for overwriting the options
    local lastrow=`get_cursor_row`
    local lastcol=`get_cursor_col`
    local startrow=1
    local startcol=1

    # 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

    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 = "k" ]]; then echo up; fi;
        if [[ $key = "j" ]]; then echo down; fi;
        if [[ $key = "h" ]]; then echo left; fi;
        if [[ $key = "l" ]]; then echo right; fi;
        if [[ $key = "a" ]]; then echo all; fi;
        if [[ $key = "n" ]]; then echo none; fi;
        if [[ $key = $'\x1b' ]]; then
            read -rsn2 key
            if [[ $key = [A || $key = k ]]; then echo up;    fi;
            if [[ $key = [B || $key = j ]]; then echo down;  fi;
            if [[ $key = [C || $key = l ]]; then echo right;  fi;
            if [[ $key = [D || $key = h ]]; then echo left;  fi;
        fi 
    }

    toggle_option() {
        local option=$1
        if [[ ${selected[option]} == true ]]; then
            selected[option]=false
        else
            selected[option]=true
        fi
    }

    toggle_option_multicol() {
        local option_row=$1
        local option_col=$2

    if [[ $option_row -eq -10 ]] && [[ $option_row -eq -10 ]]; then
        for ((option=0;option<${#selected[@]};option++)); do
                    selected[option]=true
        done
    else
        if [[ $option_row -eq -100 ]] && [[ $option_row -eq -100 ]]; then
            for ((option=0;option<${#selected[@]};option++)); do
                        selected[option]=false
            done
        else
            option=$(( $option_col + $option_row * $colmax )) 

                if [[ ${selected[option]} == true ]]; then
                        selected[option]=false
                else
                    selected[option]=true
                fi
            fi
    fi

    }

    print_options_multicol() {
        # print options by overwriting the last lines
        local curr_col=$1
        local curr_row=$2
        local curr_idx=0

        local idx=0
        local row=0
        local col=0

    curr_idx=$(( $curr_col + $curr_row * $colmax ))

        for option in "${options[@]}"; do
            local prefix="[ ]"
            if [[ ${selected[idx]} == true ]]; then
              prefix="[\e[38;5;46m✔\e[0m]"
            fi

            row=$(( $idx/$colmax ))
        col=$(( $idx - $row * $colmax ))

            cursor_to $(( $startrow + $row + 1)) $(( $offset * $col + 1))
            if [ $idx -eq $curr_idx ]; then
                print_active "$option" "$prefix"
            else
                print_inactive "$option" "$prefix"
            fi
            ((idx++))
        done
    }


    local active_row=0
    local active_col=0


    while true; do
        print_options_multicol $active_col $active_row 

        # user key control
        case `key_input` in
            space)  toggle_option_multicol $active_row $active_col;;
            enter)  print_options_multicol -1 -1; break;;
            up)     ((active_row--));
                    if [ $active_row -lt 0 ]; then active_row=0; fi;;
            down)   ((active_row++));
                    if [ $active_row -ge $(( ${#options[@]} / $colmax ))  ]; then active_row=$(( ${#options[@]} / $colmax )); fi;;
            left)     ((active_col=$active_col - 1));
                    if [ $active_col -lt 0 ]; then active_col=0; fi;;
            right)     ((active_col=$active_col + 1));
                    if [ $active_col -ge $colmax ]; then active_col=$(( $colmax -1 )) ; fi;;
            all)    toggle_option_multicol -10 -10 ;;
            none)   toggle_option_multicol -100 -100 ;;
        esac
    done

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

    eval $return_value='("${selected[@]}")'
    clear
}

function multiselect_43m {
    # little helpers for terminal print control and key input
    ESC=$( printf "\033")
    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#*[}; }
    get_cursor_col()    { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${COL#*[}; }

    local return_value=$1
    local colmax=$2
    local offset=$3
    local size=$4
    shift 4

    local options=("$@")
    shift $size

    for i in $(seq 0 $size); do
        unset options[$(( $i + $size ))]
    done

    local defaults=("$@")
    shift $size

    unset defaults[$size]

    local title="$@"

#   local options=("${!tmp_options}")
#   local defauts=("${!tmp_defaults}")

    local LINES=$( tput lines )
    local COLS=$( tput cols )

    clear

#   checkwinsize $(( ${#options[@]}/$colmax )) $LINES
#   echo ${#options[@]}/$colmax
#   exit

    err=`checkwinsize $(( ${#options[@]}/$colmax )) $(( $LINES - 2)); echo $?`

    if [[ ! $err == 0 ]]; then
        echo "La taille de votre fenêtre est de $LINES lignes, incompatible avec le menu de ${#_liste[@]} items..."
            cursor_to $lastrow
        exit
    fi 

    local selected=()
    for ((i=0; i<${#options[@]}; i++)); do
        if [[ ${defaults[i]} = "true" ]]; then
            selected+=("true")
        else
            selected+=("false")
        fi
        printf "\n"
    done

    cursor_to $(( $LINES - 2 ))
    printf "_%.s" $(seq $COLS)
    echo -e "$bleuclair / $title / | $vertfonce select : key [space] | (un)select all : key ([n])[a] | move : arrow up/down/left/right or keys k/j/l/h | validation : [enter] $neutre\n" | column  -t -s '|'
     
    # determine current screen position for overwriting the options
    local lastrow=`get_cursor_row`
    local lastcol=`get_cursor_col`
    local startrow=1
    local startcol=1

    # 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

    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 = "k" ]]; then echo up; fi;
        if [[ $key = "j" ]]; then echo down; fi;
        if [[ $key = "h" ]]; then echo left; fi;
        if [[ $key = "l" ]]; then echo right; fi;
        if [[ $key = "a" ]]; then echo all; fi;
        if [[ $key = "n" ]]; then echo none; fi;
        if [[ $key = $'\x1b' ]]; then
            read -rsn2 key
            if [[ $key = [A || $key = k ]]; then echo up;    fi;
            if [[ $key = [B || $key = j ]]; then echo down;  fi;
            if [[ $key = [C || $key = l ]]; then echo right;  fi;
            if [[ $key = [D || $key = h ]]; then echo left;  fi;
        fi 
    }

    toggle_option() {
        local option=$1
        if [[ ${selected[option]} == true ]]; then
            selected[option]=false
        else
            selected[option]=true
        fi
    }

    toggle_option_multicol() {
        local option_row=$1
        local option_col=$2

    if [[ $option_row -eq -10 ]] && [[ $option_row -eq -10 ]]; then
        for ((option=0;option<${#selected[@]};option++)); do
                    selected[option]=true
        done
    else
        if [[ $option_row -eq -100 ]] && [[ $option_row -eq -100 ]]; then
            for ((option=0;option<${#selected[@]};option++)); do
                        selected[option]=false
            done
        else
            option=$(( $option_col + $option_row * $colmax )) 

                if [[ ${selected[option]} == true ]]; then
                        selected[option]=false
                else
                    selected[option]=true
                fi
            fi
    fi

    }

    print_options_multicol() {
        # print options by overwriting the last lines
        local curr_col=$1
        local curr_row=$2
        local curr_idx=0

        local idx=0
        local row=0
        local col=0

    curr_idx=$(( $curr_col + $curr_row * $colmax ))

        for option in "${options[@]}"; do
            local prefix="[ ]"
            if [[ ${selected[idx]} == true ]]; then
              prefix="[\e[38;5;46m✔\e[0m]"
            fi

            row=$(( $idx/$colmax ))
        col=$(( $idx - $row * $colmax ))

            cursor_to $(( $startrow + $row + 1)) $(( $offset * $col + 1))
            if [ $idx -eq $curr_idx ]; then
                print_active "$option" "$prefix"
            else
                print_inactive "$option" "$prefix"
            fi
            ((idx++))
        done
    }


    local active_row=0
    local active_col=0
    while true; do
        print_options_multicol $active_col $active_row 

        # user key control
        case `key_input` in
            space)  toggle_option_multicol $active_row $active_col;;
            enter)  print_options_multicol -1 -1; break;;
            up)     ((active_row--));
                    if [ $active_row -lt 0 ]; then active_row=0; fi;;
            down)   ((active_row++));
                    if [ $active_row -ge $(( ${#options[@]} / $colmax ))  ]; then active_row=$(( ${#options[@]} / $colmax )); fi;;
            left)     ((active_col=$active_col - 1));
                    if [ $active_col -lt 0 ]; then active_col=0; fi;;
            right)     ((active_col=$active_col + 1));
                    if [ $active_col -ge $colmax ]; then active_col=$(( $colmax -1 )) ; fi;;
            all)    toggle_option_multicol -10 -10 ;;
            none)   toggle_option_multicol -100 -100 ;;
        esac
    done

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

    eval $return_value='("${selected[@]}")'
    clear
}

example_menu.sh:

#!/bin/bash

if [ -e./menu.sh ]; then
    source./menu.sh
else
    echo "script menu.sh introuvable dans le répertoire courant"
    exit
fi

LINES=$( tput lines )
COLS=$( tput cols )

clear

#Définition de mes listes 

for ((i=0; i<128; i++)); do
    _liste[i]="Choix $i"
    _preselection_liste[i]=false
done

colmax=3
offset=$(( $COLS / $colmax ))

VERSION=`echo $BASH_VERSION | awk -F\( '{print $1}' | awk -F. '{print $1"."$2}'`

if [ $(echo "$VERSION >= 4.3" | bc -l) -eq 1 ]; then
    multiselect_43p result $colmax $offset _liste _preselection_liste "CHOIX DU DEPOT" 
else
    multiselect_43m result $colmax $offset ${#_liste[@]} "${_liste[@]}" "${_preselection_liste[@]}" "CHOIX DU DEPOT" 
fi

idx=0
dbg=1
status=1
for option in "${_liste[@]}"; do
    if  [[ ${result[idx]} == true ]]; then
        if [ $dbg -eq 0 ]; then
                echo -e "$option\t=> ${result[idx]}"
        fi
        TARGET=`echo $TARGET ${option}`
        status=0
    fi  
        ((idx++))
done

if [ $status -eq 0 ] ; then
    echo -e "$vertfonce Choix des items validé :\n$vertclair $TARGET $neutre"
else
    echo -e "$rougefonce Aucun choix d'items détecté... $neutre"
    exit
fi

while true; do
    case `key_input` in
            enter)  break;;
        esac
done

clear

Screenshot

0
24.11.2021, 18:03

Теги

Похожие вопросы