我正在寻找一种在 shell 中显示内联菜单的工具,可以使用箭头键和 Enter 进行导航。 “内联”是指菜单显示在标准输出文本的正常流程中,不是在所有内容之上的弹出对话框中。
我只发现那个帖子试图解决这个问题,但它只提到自定义脚本或非内联/弹出解决方案(如dialog
或zenity
)。
我正在寻找的是一个强大的包,我可以使用apt-get
或简单地在 Docker 映像中安装它npm install -g
,并使用选项列表从我的脚本中调用并获取用户选择的项目。
在nodeJS中,我正在使用询问者它不仅提供此类菜单,还提供各种输入。
这是一个例子截屏这样的内联菜单。
该工具不必用 shell 脚本编写。它可以是用任何语言编写的二进制/脚本,只要使用apt-get
/很容易安装即可curl
。即使是一个 nodeJS 工具也可以,只要它可以从 shell 脚本调用来传递选择。
答案1
我以前用过i选择为此,许多年前。
A非常基本示例:
$ sel="$(iselect -a 'foo' 'bar')"
$ echo $sel
foo
从man iselect
:
iSelect 是一个用于 ASCII 文件的交互式行选择工具,通过基于 Curses 的全屏终端会话进行操作。它可以用作由 Bourne-Shell、Perl 或其他类型的脚本后端控制的用户界面前端作为其包装器,也可以批量用作管道过滤器(通常在 grep 和最终执行命令之间)。换句话说:iSelect 被设计用于任何类型的基于行的交互选择。
输入数据
输入可以从命令行 (line1 line2 ...) 读取,其中每个参数对应一个缓冲区行,也可以从 stdin(当未给出参数时)读取输入,其中缓冲区行根据换行符确定。
"<b>"..."</b>"
您还可以使用HTML 中的构造,让不可选择的行的子字符串以粗体模式显示(因为可选择的行始终显示为粗体) 。
答案2
一个非常基本的方法是使用bash
'sselect
语句;无需安装任何东西(其他)。这是我手头刚刚得到的一个例子:
#!/bin/bash
[...]
sourceBranch=
targetBranch=
# Force one option per line
columnsBackup=${COLUMNS}
COLUMNS=40
echo "Select source and target branch:"
select branches in \
"testing -> release-candidate" \
"release-candidate -> stable-release" \
"stable-release -> stable"
do
if [ -z "${branches}" ]; then
echo "Invalid selection"
continue
fi
sourceBranch="${branches%% -> *}"
targetBranch="${branches##* -> }"
break
done
COLUMNS=${columnsBackup}
echo "Releasing from ${sourceBranch} to ${targetBranch}"
[...]
输出:
Select source and target branch:
1) testing -> release-candidate
2) release-candidate -> stable-release
3) stable-release -> stable
#? 1
Releasing from testing to release-candidate
您可能会case ... esac
在块中进行一些处理do ... done
。
答案3
这是我使用 bash 对这个问题的看法。
#!/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 ...)
figlet -st "$COLUMNS" "Welcome $USER"
printf '\n?%s\n?%s\n?%s\n\n' "What's the name of your website simple-site" "What's the description of your website(optional):" "Please choose lincense":
# Change the value of options to whatever you want to use.
options=("MIT" "Apache-2.0" "GPL-3.0" "Others")
select_option (){
# little helpers for terminal print control and key input
ESC=$(printf '%b' "\033")
cursor_blink_on() {
printf '%s' "$ESC[?25h"
}
cursor_blink_off() {
printf '%s' "$ESC[?25l"
}
cursor_to() {
printf '%s' "$ESC[$1;${2:-1}H"
}
print_option() {
printf ' %s ' "$1"
}
print_selected() {
printf ' %s' "$ESC[7m $1 $ESC[27m"
}
get_cursor_row() {
IFS=';' read -sdR -p $'\E[6n' ROW COL; printf '%s' ${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 == $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 < 0 )); then selected=$(($# - 1)); fi;;
down) ((selected++));
if (( selected > $# )); then selected=0; fi;;
esac
done
# cursor position back to normal
cursor_to $lastrow
printf "\n"
cursor_blink_on
return "$selected"
}
select_option "${options[@]}"
choice=$?
index=$choice
value=${options[$choice]}
case $value in
MIT) ## User selected MIT
read -rp "Really use? $value [Y/N] " answer
[[ $answer ]] || { echo "No answer!" >&2; exit 1; }
if [[ $answer == [Yy] ]]; then
: ## User selected Y or y, what are you going to do about it?
elif [[ $answer == [Nn] ]]; then
: ## User selected N or n what are you going to do about it?
fi
printf '%s\n' "You have choosen $answer";;
Apache-2.0)
read -rp "Really use? $value [Y/N] " answer
[[ $answer ]] || { echo "No answer!" >&2; exit 1; }
if [[ $answer == [Yy] ]]; then
:
elif [[ $answer == [Nn] ]]; then
:
fi
;;
GPL-3.0)
read -rp "Really use? $value [Y/N] " answer
[[ $answer ]] || { echo "No answer!" >&2; exit 1; }
if [[ $answer == [Yy] ]]; then
:
elif [[ $answer == [Nn] ]]; then
:
fi
;;
Others)
read -rp "Really use? $value [Y/N] " answer
[[ $answer ]] || { echo "No answer!" >&2; exit 1; }
if [[ $answer == [Yy] ]]; then
:
elif [[ $answer == [Nn] ]]; then
:
fi
;;
esac
输出或多或少是在https://i.stack.imgur.com/RO9E5.png:
if 语句内不执行任何操作,请替换 为:
您的代码/流程或您想要执行的任何操作,如果答案是[Yy]
或[Nn]
这应该足以让您开始。顺便说一下,我发现发布在某处的捕捉运动的代码我刚刚扩展/重写了一些语法。