두 개 이상의 변수 상태를 비교하려고 합니다. 사용 사례는 다른 옵션 중에서 사용 가능한 실행 파일을 기반으로 여러 "모드" 중 하나만 선택(또는 자동 선택)해야 하는 스크립트입니다. 일부 구문 다이어그램은 다음과 같습니다.
[ [--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
종속성으로 필요합니다 .
저는 배쉬 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
다른 문제가 있을 수 있습니다. 모든 관련 정보를 제공하는 것이 중요합니다.