创建允许您选择多个选项而不是只选择其中一个选项的 bash 脚本?

创建允许您选择多个选项而不是只选择其中一个选项的 bash 脚本?

我正在考虑创建一个 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()函数中解决了多项选择问题,该函数充当了dialogwith--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 "$@"

进一步研究:

相关内容