Phím mũi tên / Nhập menu


11

Làm cách nào để tạo menu trong tập lệnh shell sẽ hiển thị 3 tùy chọn mà người dùng sẽ sử dụng các phím mũi tên để di chuyển con trỏ tô sáng và nhấn enter để chọn một tùy chọn?


Tôi nghĩ rằng bạn không may mắn khi WRT có chức năng phím mũi tên và làm nổi bật trong tập lệnh shell thuần (bạn có thể làm điều sau với tput, nhưng tôi nghĩ rằng điều này là không thể), nhưng bạn có thể tạo các menu đơn giản trong bash với select: tldp.org/LDP/Bash-Beginners-Guide/html/sect_09_06.html
goldilocks

Bạn có nghĩa là một menu GUI (sử dụng một cái gì đó như [zenity] (Ben Browder) hoặc một cái dựa trên văn bản bằng cách sử dụng một cái gì đó như ncurses ?
terdon

Tôi đang cố gắng tạo một menu giống như menu bạn nhận được nếu bạn phải chọn tùy chọn khởi động cho windows ("chế độ an toàn" "bình thường", v.v.)
Mrplow911

1
dialoggói tạo giao diện đầu cuối giả-GUI cơ bản trong tập lệnh.
HalosGhost

@HalosGhost Bạn có biết ví dụ nào về điều này không?
Mrplow911

Câu trả lời:


9

Hộp thoại là một công cụ tuyệt vời cho những gì bạn đang cố gắng để đạt được. Dưới đây là ví dụ về menu 3 lựa chọn đơn giản:

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

Cú pháp như sau:

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

Các lựa chọn sẽ được gửi đến stderr. Đây là một kịch bản mẫu sử dụng 3 màu.

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

Trên Debian, bạn có thể cài đặt dialogthông qua gói cùng tên .


22

Đây là một bashgiải pháp tập lệnh thuần túy dưới dạng select_optionhàm, chỉ dựa vào các chuỗi thoát ANSI và tích hợp sẵn read.

Hoạt động trên Bash 4.2.45 trên OSX. Các phần thú vị có thể không hoạt động tốt như nhau trong tất cả các môi trường từ tất cả những gì tôi biết là get_cursor_row(), key_input()(để phát hiện các phím lên / xuống) và các cursor_to()chức năng.

#!/usr/bin/env bash

# Renders a text based list of options that can be selected by the
# user using up, down and enter keys and returns the chosen option.
#
#   Arguments   : list of options, maximum of 256
#                 "opt1" "opt2" ...
#   Return value: selected index (0 for opt1, 1 for opt2 ...)
function select_option {

    # 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_option()     { printf "   $1 "; }
    print_selected()   { printf "  $ESC[7m $1 $ESC[27m"; }
    get_cursor_row()   { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${ROW#*[}; }
    key_input()        { read -s -n3 key 2>/dev/null >&2
                         if [[ $key = $ESC[A ]]; then echo up;    fi
                         if [[ $key = $ESC[B ]]; then echo down;  fi
                         if [[ $key = ""     ]]; then echo enter; fi; }

    # initially print empty new lines (scroll down if at bottom of screen)
    for opt; do printf "\n"; done

    # determine current screen position for overwriting the options
    local lastrow=`get_cursor_row`
    local startrow=$(($lastrow - $#))

    # 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 selected=0
    while true; do
        # print options by overwriting the last lines
        local idx=0
        for opt; do
            cursor_to $(($startrow + $idx))
            if [ $idx -eq $selected ]; then
                print_selected "$opt"
            else
                print_option "$opt"
            fi
            ((idx++))
        done

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

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

    return $selected
}

Dưới đây là một ví dụ sử dụng:

echo "Select one option using up/down keys and enter to confirm:"
echo

options=("one" "two" "three")

select_option "${options[@]}"
choice=$?

echo "Choosen index = $choice"
echo "        value = ${options[$choice]}"

Đầu ra trông giống như bên dưới, với tùy chọn hiện được chọn được tô sáng bằng cách sử dụng màu ansi nghịch đảo (khó truyền tải ở đây trong phần đánh dấu). Điều này có thể được điều chỉnh trong print_selected()chức năng nếu muốn.

Select one option using up/down keys and enter to confirm:

  [one] 
   two 
   three 

Cập nhật: Đây là một phần mở rộng nhỏ select_optgói select_optionchức năng trên để dễ sử dụng trong casecâu lệnh:

function select_opt {
    select_option "$@" 1>&2
    local result=$?
    echo $result
    return $result
}

Ví dụ sử dụng với 3 tùy chọn bằng chữ:

case `select_opt "Yes" "No" "Cancel"` in
    0) echo "selected Yes";;
    1) echo "selected No";;
    2) echo "selected Cancel";;
esac

Bạn cũng có thể trộn nếu có một số mục đã biết (Có và Không trong trường hợp này) và tận dụng mã thoát $?cho trường hợp ký tự đại diện:

options=("Yes" "No" "${array[@]}") # join arrays to add some variable array
case `select_opt "${options[@]}"` in
    0) echo "selected Yes";;
    1) echo "selected No";;
    *) echo "selected ${options[$?]}";;
esac

1
Điều này thật đẹptuyệt vời ; cảm ơn bạn rất nhiều vì đã chia sẻ Đây có phải là ban đầu của riêng bạn? Có một repo trực tuyến để nhân bản / ngã ba? Điều duy nhất tôi có thể thấy rằng dường như là trong kiểm soát phiên bản là trên GitHub trong stephenmm 's Gist (với dòng chỉnh sửa bổ sung) mà điểm trở lại tới đây, lol. Làm việc trên các sửa đổi của riêng tôi (trong Gist, nhưng dự định thực hiện repo) ở đây mặc dù tôi vẫn cần cập nhật với những thay đổi mới nhất.
l3l_aze

1
Tôi đã sử dụng nó trong một số mã không công khai. Kéo nó lại với nhau từ các bit và phần khác nhau được tìm thấy trên web :-)
Alexander Klimetschek

Ồ; công việc tốt đẹp. Tôi đã bắt đầu một repo với các sửa đổi của mình tại https://github.com/l3laze/sind . Cho đến nay, sự khác biệt lớn nhất là nâng cấp xử lý đầu vào và bổ sung một thanh tiêu đề. Tôi hy vọng sẽ thêm chỉnh sửa một dòng và nhiều dòng, nhưng chưa làm được gì với những thứ đó ngoài việc xem một số mã
l3l_aze
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.