首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何正确地使用具有多个变量的&和_

如何正确地使用具有多个变量的&和_
EN

Unix & Linux用户
提问于 2020-09-23 18:18:17
回答 3查看 369关注 0票数 0

我试着比较两个以上变量的状态。用例是一个脚本,在其他选项中,应该根据可用的可执行文件选择(或自动选择)几种“模式”中的一种。部分语法图是:

代码语言:javascript
复制
 [ [--fzf,-f]|[--rofi,-r]|[--dmenu,-d] ]

这些变量是基于命令参数的存在而定义的,因此,例如,如果在命令行参数中找到--fzf-f,则关联的fzf变量被设置为"1“,表示用户希望在fzf mode中运行脚本,因为没有更好的条件。

下面的&&操作符语句解决了如果在命令行中找不到任何命令参数会发生什么。基本上,如果没有选择“模式”,那么脚本将自动选择一个模式,并且只有一个模式,以分层的方式使用。

下面的||操作符语句应该解决如果选择模式(由用户选择),但找不到底层可执行文件时会发生什么情况。

以下是&&运算符的原始版本:

代码语言:javascript
复制
if [[ $fzf = 0 && $rofi = 0 ]]; then
        if command_exists fzf; then
            fzf=1
        elif command_exists rofi; then
            rofi=1
        fi
    fi

代码语言:javascript
复制
if [[ $fzf = 0 && $rofi = 0 && $dmenu = 0 ]]; then
        if command_exists fzf; then
            fzf=1
        elif command_exists rofi; then
            rofi=1
        elif command_exists dmenu; then
            dmenu=1
        fi
    fi

最后,在这里,用原值表示的连取操作符:

代码语言:javascript
复制
if [[ $rofi = 1 || $fzf = 0 ]]; then
        command_exists rofi || die "Could not find rofi in \$PATH"
        menu="$rofi_cmd"
elif [[ $fzf = 1 || $rofi = 0 ]]; then
        command_exists fzf || die "Could not find fzf in \$PATH"
        menu="$fzf_cmd"
else
        die "Could not find either fzf or rofi in \$PATH"
fi

代码语言:javascript
复制
if [[ $rofi = 1 || $fzf = 0 || $dmenu = 0 ]]; then
        command_exists rofi || die "Could not find rofi in \$PATH"
        menu="$rofi_cmd"
    elif [[ $fzf = 1 || $rofi = 0 || $dmenu = 0 ]]; then
        command_exists fzf || die "Could not find fzf in \$PATH"
        menu="$fzf_cmd"
    elif [[ $dmenu = 1 || $rofi = 0 || $fzf = 0 ]]; then
        command_exists dmenu || die "Could not find dmenu in \$PATH"
        menu="$dmenu_cmd"
    else
        die "Could not find either fzf or rofi or dmenu in \$PATH"
    fi

这似乎不会抛出任何错误,但我怀疑这不是正确的方法,而且可能不像预期的那样工作(因为在使用-x并看到它的输出时,它似乎报告了错误的值)。

我知道有像 1这样的帖子,但是我还没有(还)找到有两个以上变量的例子(就像我在上面做的那样)。

以上部分是从脚本中提取的。我基本上是想添加对dmenu的支持,因为它只支持rofifzf (如上面所示)。

这里是完全修改的脚本。它需要password-store作为依赖项。

我用的是Bash 5.0.3。

如何正确地使用具有多个变量的&和_

EN

回答 3

Unix & Linux用户

回答已采纳

发布于 2020-09-23 20:49:00

||&&运营者运作良好。在翻译脚本的方式上存在问题,但是,尽管一再要求逻辑上的澄清,但没有提供任何问题。因此,我根据我如何理解复制的脚本工作来补充这个问题。

一件有趣的事情是,问题中没有张贴的部分脚本被翻译错了:

代码语言:javascript
复制
if [[ $fzf = 1 && $rofi = 1 && $dmenu = 1 ]]; then
    die 'Either --fzf,-f or --rofi,-r or --dmenu,-d must be given, not more than one'
fi

最重要的是,在快速审查之后才能说出的意图是,这一声明应该更符合以下几点:

代码语言:javascript
复制
if [[ $(( $fzf + $rofi + $dmenu )) > 1 ]]; then
    die 'Either --fzf,-f or --rofi,-r or --dmenu,-d must be given, not more than one'
fi

可能还有其他问题。你提供所有相关信息是非常重要的。

票数 3
EN

Unix & Linux用户

发布于 2020-09-23 21:05:56

如果用户应该只选择其中一个,我只需要使用一个变量来保存选择,删除每个选项变量。无论如何,我们并不真正关心所有的组合,我们只想选择三个中的一个,而另一个选择是"unset/default“。

所以:

代码语言:javascript
复制
#!/bin/sh
cmd=             # empty value for default
case "$1" in
    --rofi|-r)  cmd=rofi ;;
    --fzf|-f)   cmd=fzf ;;
    --dmenu|-d) cmd=dmenu ;;
esac

if [ -z "$cmd" ]; then
    echo "no command set, looking for default"
    if command_exists fzf; then
        cmd=fzf
    elif
        ...
    fi
fi

echo "running with command $cmd"
# actually do something

在这里,选择的模式存储在cmd中。实际上,我甚至没有给用户提供两个命令的可能性,只为标志读取第一个参数。现在,如果您使用getoptgetopts,这并不是真正的问题,但是我们可以在设置它之前检查是否已经设置了该模式(再次)。

代码语言:javascript
复制
#!/bin/sh
error_if_cmd_set() {
    if [ -n "$1" ]; then
        echo "command already set"
        exit 1
    fi
}
cmd=
for arg in "$@"; do
    case "$1" in
        --rofi|-r)  error_if_cmd_set "$cmd"; cmd=rofi ;;
        --fzf|-f)   error_if_cmd_set "$cmd"; cmd=fzf ;;
        --dmenu|-d) error_if_cmd_set "$cmd"; cmd=dmenu ;;
    esac
done
# ...
echo "using command $cmd"
票数 5
EN

Unix & Linux用户

发布于 2020-09-23 18:55:19

我真的不知道你想用那些支票做什么。如果您需要检查这些程序中至少有一个可用:

代码语言:javascript
复制
programs=(fzf rofi dmenu)
available=()

for prog in "${programs[@]}"; do
  location=$(type -P $prog) && available+=("$location")
done

(( ${#available[@]} == 0 )) && die "none of ${programs[*] are available"

# what is your logic for choosing one if multiple are available?
menu=${available[0]}

根据您的评论,将更多的工作推入案例分支会更清晰:

代码语言:javascript
复制
    fzf_exists=0
    rofi_exists=0
    dmenu_exists=0

    # reorder these if you want: the _last_ one to succeed is the default
    if command_exists dmenu; then
        dmenu_exists=1
        menu_default=$dmenu_cmd
    fi
    if command_exists rofi; then 
        rofi_exists=1
        menu_default=$rofi_cmd
    fi
    if command_exists fzf; then 
        fzf_exists=1
        menu_default=$fzf_cmd
    fi

    if [[ -z $menu_default ]]; then
        die "none of fzf, rofi, dmenu are available"
    fi

    while true; do 
        case "$1" in
            -f|--fzf) 
                (( fzf_exists )) || die "fzf is not available"
                [[ -n $menu ]]   && die "choose only one of fzf/rofi/dmenu"
                menu=$fzf_cmd
                shift 
                ;;
            -r|--rofi)
                (( rofi_exists )) || die "rofi is not available"
                [[ -n $menu ]]    && die "choose only one of fzf/rofi/dmenu"
                menu=$rofi_cmd
                shift 
                ;;
            -d|--dmenu)
                (( dmenu_exists )) || die "dmenu is not available"
                [[ -n $menu ]]     && die "choose only one of fzf/rofi/dmenu"
                menu=$dmenu_cmd
                shift 
                ;;
            # ...
        esac
    done

    : ${menu:=$menu_default}

注意,command_exists函数应该是return 1而不是exit 1

票数 4
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/611001

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档