我正在尝试比较两个以上变量的状态。用例是一个脚本,除其他选项外,应根据可用的可执行文件仅选择(或自动选择)几种“模式”中的一种。部分语法图是:
[ [--fzf,-f]|[--rofi,-r]|[--dmenu,-d] ]
这些变量是根据命令参数的存在来定义的,因此,例如,如果在命令行参数上找到--fzf
或,则关联的变量将设置为“1”,表示用户想要运行脚本,因为缺乏更好的方法条款,.-f
fzf
fzf mode
下面的运算符语句&&
解决了如果在命令行上找不到任何命令参数时会发生的情况。基本上,如果未选择“模式”,则脚本将自动选择一种且仅一种模式以分层方式使用。
下面的运算符语句||
应该解决如果(由用户)选择模式但未找到底层可执行文件时会发生的情况。
这是 && 运算符的原始版本:
if [[ $fzf = 0 && $rofi = 0 ]]; then
if command_exists fzf; then
fzf=1
elif command_exists rofi; then
rofi=1
fi
fi
到
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
最后,这里是 || 的原文。操作员:
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
到
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
和查看其输出时似乎报告了错误的值)。
我知道诸如此类的帖子这一,但我(还)没有找到具有两个以上变量的示例(就像我上面尝试做的那样)。
以上原文部分摘自这脚本。我基本上试图添加对的支持,dmenu
因为它只支持rofi
和fzf
(如上所示)。
这里是完整修改的脚本。它需要password-store
作为依赖项。
我正在使用 Bash 5.0.3。
如何正确地将 && 和 || 运算符用于两个以上的变量?
答案1
如果用户只需要选择其中之一,我只需使用一个变量来保存选择,并删除每个选项的变量。无论如何,我们并不真正关心所有组合,我们只想从三个组合中选择一个,另一个用于“未设置/默认”。
所以:
#!/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
。实际上,我什至没有给用户发出两个命令的可能性,只读取第一个参数作为标志。现在,如果您使用getopt
或getopts
,那并不能真正实现,但我们可以在设置之前检查模式是否已经设置(再次)。
#!/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"
答案2
老实说,我不知道你想用这些支票做什么。如果您需要检查这些程序中至少有一个可用:
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]}
根据您的评论,将更多工作推入案例分支会更干净:
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
答案3
和操作||
员&&
工作正常。剧本的翻译方式存在问题,但尽管一再要求澄清逻辑,但没有得到任何答复。因此,我根据我如何理解复制的脚本正在工作,添加了这个问题。
一件有趣的事情是,问题中未发布的一些脚本被错误地翻译了:
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
快速回顾后可以看出,其意图是该声明应该更多地遵循以下内容:
if [[ $(( $fzf + $rofi + $dmenu )) > 1 ]]; then
die 'Either --fzf,-f or --rofi,-r or --dmenu,-d must be given, not more than one'
fi
可能还有其他问题。提供所有相关信息非常重要。