![创建允许您选择多个选项而不是只选择其中一个选项的 bash 脚本?](https://linux22.com/image/1162173/%E5%88%9B%E5%BB%BA%E5%85%81%E8%AE%B8%E6%82%A8%E9%80%89%E6%8B%A9%E5%A4%9A%E4%B8%AA%E9%80%89%E9%A1%B9%E8%80%8C%E4%B8%8D%E6%98%AF%E5%8F%AA%E9%80%89%E6%8B%A9%E5%85%B6%E4%B8%AD%E4%B8%80%E4%B8%AA%E9%80%89%E9%A1%B9%E7%9A%84%20bash%20%E8%84%9A%E6%9C%AC%EF%BC%9F.png)
我正在考虑创建一个 bash 脚本,其中可以指定多个选项,最后根据所选选项定义变量或在收到不同选项时执行某些命令。一个例子胜过千言万语:
[X] 仅复制 (1) - 用户输入的选项 [ ] 仅移动 (2) [X] 校验和 (3) - 用户输入的选项 [ ] 重置权限 (4) [ ] 退出 (5) 选择选项:
我找到了一些选项,但我不知道如何让它们执行某种功能,因为我不明白代码是如何工作的。
更新:
代码功能:
/bin/bash #!/bin/bash #Sergiy Kolodyazhnyy 贡献代码并为 MarianoM 改编。 resize -s 40 90 > /dev/null #更改窗口大小。 选项 = $(对话框 --clear --backtitle“同步......” --title“同步” \ --checklist "选择同步选项:" 20 50 10 \ 校验和“比较内容”关闭\ 详细信息“显示更多信息”关闭\ 目录“同步文件夹”上 \ 递归“包括子文件夹”关闭 2>&1 > /dev/tty) for i in $option; do #设置菜单选项的参数。 案例 $i 在 校验和)c="-c" ;; 细节)v="-v" ;; 目录)d="-d" ;; 递归)r="-r" ;; 埃萨克 完毕 if [ -z $option ]; then #检查变量是否为空。如果为空,则表示用户尚未选择选项。 清除 回声 echo “错误:未选择任何选项或未安装对话框。程序无法继续。” 回声 别的 清除 源 = $ (dialog --clear --backtitle "请选择源..." --title "源:" --fselect "" 20 50 2>&1 > /dev/tty) 如果 [ -z $source ]; 那么 清除 回声 echo "错误程序。未选择源,请重试!" 回声 出口 菲 清除 目的地 = $(对话框 --clear --backtitle“请选择目的地......”--title“目的地:”--fselect“”20 50 2>&1 > /dev/tty) 如果 [ -z $目的地 ]; 那么 清除 回声 echo "错误程序。未选择目的地,请重试!" 回声 出口 菲 清除 rsync“$c”“$v”“$d”“$r”“$源”“$目标” 回声 菲 出口
答案1
从评论中的讨论可以看出,您主要关心的是创建具有多个选择的脚本,而不是专注于复制/移动文件本身,文件操作只是一个例子。此功能可以通过dialog
命令实现,该命令允许创建文本用户界面,--checklist
特别是带有标志;但是,标准 shell 专用工具箱中没有任何东西可以实现您想要的功能。因此,dialog
是这项工作的合适工具。
下面您将看到一个示例脚本。虽然该脚本仅实现了讨论过的 3 个选项,但它提供了一个不错的起点,用户可以进一步扩展,并且还解决了评论中提到的互斥选项。特别是,menu()
函数中解决了多项选择问题,该函数充当了dialog
with--checklist
选项的包装器
为了简单起见,你真正需要的只是这些:
output=$(dialog --clear --backtitle "Backtitle. Use <SPACE> to select." --title "My Dialog" \
--checklist "Select all that apply" 50 50 100 \
checksum "SHA-256" off \
copy "Copy only (exclusive with move)" off \
move "Move only (exclusive with copy)" off 2>&1 > /dev/tty)
这会将多个项目的选择保存到变量中$output
。请注意,末尾的 `2>&1 > /dev/tty) 对于将返回值保存到变量中至关重要。但请参阅下面的脚本以获取更实际的示例:
#!/bin/bash
puke(){
# function to exit with specific error message
# analogous to 'die' in Perl
printf ">>> Errors were encountered: %s\n" "$1" && exit
} > /dev/stderr
menu(){
# dialog --help documents the option as follows:
# --checklist <text> <height> <width> <list height> <tag1> <item1> <status1>...
# tags are what the output returns.
# We can use word-splitting
# and iterate over output of this function in order. Of course first option
# being checksum will always work and is not mutually exclusive with anything else
dialog --clear --backtitle "Backtitle. Use <SPACE> to select." --title "My Dialog" \
--checklist "Select all that apply" 50 50 100 \
checksum "SHA-256" off \
copy "Copy only (exclusive with move)" off \
move "Move only (exclusive with copy)" off || puke
} 2>&1 1>/dev/tty
select_file(){
dialog --backtitle "Choose file by typing or navigating and selecting with <SPACE>" --fselect "/etc/" \
20 50 || puke
} 2>&1 1>/dev/tty
iter_actions(){
# variables are available to child functions
# Since we call iter_actions in main(), this
# function also knows about main's variable $fselect
for i ; do
case "$i" in
checksum) sha256sum "$fselect" ;;
copy) cp "$fselect" /tmp ;;
move) mv "$fselect" /tmp ;;
esac
done
}
main(){
# here I'm using /etc but you can use $PWD to default to user's
# current working directory, or accept positional parameters from command-line
# as in $1, $2 and so forth
fselect=$( select_file "/etc" )
actions=$(menu)
printf "\r%b" "\033c" # this clear the screen
case "$actions" in
*copy*move|*move*copy) puke "Mutually exclusive options selected" ;;
*) iter_actions $actions ;; # note here variable is unquoted on purpose
esac
}
# script entry point
main "$@"