複数の変数の状態を比較しようとしています。ユースケースは、他のオプションから利用可能な実行可能ファイルに基づいて複数の「モード」のうちの1つのみを選択(または自動選択)する必要があるスクリプトです。いくつかの構文図は次のとおりです。
[ [--fzf,-f]|[--rofi,-r]|[--dmenu,-d] ]
これらの変数は、コマンド引数が存在するかどうかによって定義されます。たとえば、--fzf
コマンドライン引数にまたはがある場合、関連変数は "1"に設定され、ユーザーがスクリプトを実行しようとしていることを示します。より良い方法の節が不足しています。-f
fzf
fzf mode
次の演算子ステートメントは、&&
コマンドラインにコマンドパラメータがない場合に発生する状況を説明します。デフォルトでは、「モード」を選択しないと、スクリプトは階層化された方法で使用する1つのモードのみを自動的に選択します。
次の演算子ステートメントは、||
(ユーザー)パターンを選択したがデフォルトの実行可能ファイルが見つからない場合に発生する状況に対処する必要があります。
これは&&演算子の元のバージョンです:
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
使用して出力を表示したときに誤った値を報告するようです)。
私はこれを知っていますこれしかし、(まだ)2つ以上の変数がある例が見つかりませんでした(上記で試したようなもの)。
上記の原文はいくつか抜粋されました。これスクリプト。基本的にサポートを追加しようとしています。なぜなら、サポートは(上に示されている)とサポートされてdmenu
いるからです。rofi
fzf
完全な修正は次のとおりです。スクリプト。password-store
依存関係として必要です。
私はBash 5.0.3を使用しています。
2つ以上の変数に&&と||演算子を正しく使用するには?
答え1
ユーザーがそれらのうちの1つだけを選択した場合は、変数を使用して選択内容を保持し、各オプションの変数を削除します。とにかく、私たちはすべての組み合わせにあまり興味を持っていません。 3つの中から1つを選択し、「設定解除/デフォルト」に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
。実際、私はユーザーに2つのコマンドを与える可能性さえ与えませんでした。最初のパラメータをフラグとして読むだけです。これで、または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
そしてオペレータはうまく||
いきます&&
。シナリオの翻訳方法に問題がありましたが、引き続き論理的なクリーンアップを要求しましたが、答えを受け取ることができませんでした。そのため、コピーされたスクリプトが機能していることを私がどのように理解したかに応じて、この質問を追加しました。
1つの興味深いことは、その質問に投稿されていないいくつかのスクリプトが間違って翻訳されたということです。
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
他の問題がある可能性があります。すべての関連情報を提供することが重要です。