편지

편지

이 쉘 스크립트를 어떻게 단축할 수 있습니까?

CODE="A"

if test "$CODE" = "A"
then
 PN="com.tencent.ig"
elif test "$CODE" = "a"
 then
 PN="com.tencent.ig"
elif test "$CODE" = "B"
 then
 PN="com.vng.pubgmobile"
elif test "$CODE" = "b"
 then
 PN="com.vng.pubgmobile"
elif test "$CODE" = "C"
 then
 PN="com.pubg.krmobile"
elif test "$CODE" = "c"
 then
 PN="com.pubg.krmobile"
elif test "$CODE" = "D"
 then
 PN="com.rekoo.pubgm"
elif test "$CODE" = "d"
 then
 PN="com.rekoo.pubgm"
else
 echo -e "\a\t ERROR!"
 echo -e "\a\t CODE KOSONG"
 echo -e "\a\t MELAKUKAN EXIT OTOMATIS"
 exit
fi

답변1

명령문 사용 case(이식 가능, 유사한 쉘에서 작동 sh):

case "$CODE" in
    [aA] ) PN="com.tencent.ig" ;;
    [bB] ) PN="com.vng.pubgmobile" ;;
    [cC] ) PN="com.pubg.krmobile" ;;
    [dD] ) PN="com.rekoo.pubgm" ;;
    * ) printf '\a\t%s\n' 'ERROR!' 'CODE KOSONG' 'MELAKUKAN EXIT OTOMATIS' >&2
        exit 1 ;;
esac

CODE또한 변수 이름을 모두 대문자(예: )에서 소문자 또는 대소문자 혼합(예: code또는 Code) 으로 변경하는 것이 좋습니다 . 특별한 의미를 지닌 대문자 이름이 많이 있으며, 그 중 하나를 실수로 재사용하면 문제가 발생할 수 있습니다.

추가 참고 사항: 표준 규칙은 "표준 출력"이 아닌 "표준 오류"에 오류 메시지를 보내는 것입니다 >&2. 또한 스크립트(또는 프로그램)가 실패하면 exit 1호출 컨텍스트에서 무엇이 잘못되었는지 알 수 있도록 0이 아닌 상태()로 종료하는 것이 좋습니다 . 또한 다양한 상태를 사용하여 다양한 문제를 나타낼 수도 있습니다(참조:매뉴얼 curl페이지좋은 예). (제안을 해주신 Stéphane Chazelas와 Monty Harder에게 감사드립니다.)

운영 체제, 버전, 설정 등 간에 이식성이 더 높으므로 ( 및 )를 printf사용하지 않는 것이 좋습니다. OS 업데이트에 다른 옵션으로 컴파일된 bash 버전이 포함되어 동작이 변경되었기 때문에 많은 스크립트가 손상되는 상황이 있었습니다.echo -eecho -necho

$CODE여기서는 실제로 큰따옴표가 필요하지 않습니다. 내의 문자열은 case안전하게 보존할 수 있는 몇 안 되는 컨텍스트 중 하나입니다. 하지만 특별한 이유가 없는 한 변수 참조를 큰따옴표로 묶는 것을 선호합니다. 어디가 안전하고 어디가 안전하지 않은지 추적하기 어렵기 때문에 습관적으로 큰따옴표로 인용하는 것이 더 안전합니다.

답변2

bash버전 4.0 이상을 사용한다고 가정하면 ...

CODE=A

declare -A domain

domain=(
   [a]=com.tencent.ig
   [b]=com.vng.pubgmobile
   [c]=com.pubg.krmobile
   [d]=com.rekoo.pubgm
)

PN=${domain[${CODE,,}]:?ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS}

코드에서 저는 모든 도메인 이름을 포함하는 연관 배열을 정의했습니다. 각 도메인 이름은 단일 문자 소문자 키와 연결되어 있습니다.

변수 $PN에는 배열의 소문자 값에 해당하는 도메인 이름이 할당되지만 $CODE(소문자로 변환된 값만 반환됨 ${CODE,,}) 값이 목록의 유효한 항목에 해당하지 않으면 오류와 함께 스크립트가 종료됩니다.$CODE$CODEdomain

매개변수 ${variable:?error message}대체는 (코드의 해당 필드) 값으로 확장되지만 $variable값이 비어 있고 사용할 수 없는 경우 스크립트는 오류 메시지와 함께 종료됩니다. 코드에서와 정확히 동일한 오류 메시지 형식을 얻지는 못하지만 본질적으로성능$CODE유효하지 않은 경우에도 동일:

$ bash script.sh
script.sh: line 12: domain[${CODE,,}]: ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS

문자 수에 관심이 있는 경우 문자 수를 더 줄일 수 있습니다.

CODE=A
declare -A domain=( [a]=tencent.ig [b]=vng.pubgmobile [c]=pubg.krmobile [d]=rekoo.pubgm )
PN=com.${domain[${CODE,,}]:?ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS}

불필요한 개행 문자를 제거하는 것 외에도 com.각 도메인에서도 제거했습니다(대신 배포판에 추가했습니다 PN).

위의 모든 코드는 다중 문자 값에도 작동합니다 $CODE(해당 소문자 키가 배열에 있는 경우 domain).


숫자(0부터 시작) 인덱싱 의 경우 $CODE코드가 약간 단순화됩니다.

CODE=0

domain=( com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm )
PN=${domain[CODE]:?ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS}

domain또한 한 줄에 하나의 항목이 포함된 보조 파일에서 배열을 읽는 것이 매우 쉽습니다.

CODE=0

readarray -t domain <domains.txt
PN=${domain[CODE]:?ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS}

답변3

쉘이 배열을 허용하는 경우 가장 짧은 대답은 bash의 다음 예와 같습니다.

declare -A site
site=( [a]=com.tencent.ig [b]=com.vng.pubgmobile [c]=com.pubg.krmobile [d]=com.rekoo.pubgm )

pn=${site[${code,}]}

이는 $codea, b, c 또는 d만 가능하다고 가정합니다.
그렇지 않은 경우 다음과 같은 테스트를 추가하십시오.

case ${site,} in
    a|b|c|d)        pn=${site[${code,}]};;
    *)              pn="default site"
                    printf '\a\t %s\n' 'ERROR!' 'CODE KOSONG' 'MELAKUKAN EXIT OTOMATIS'
                    exit 1
                    ;;
esac

답변4

문자를 사용하여 값의 색인을 생성합니다. 숫자를 사용하면 다음과 같이 간단해집니다.

code=1
set -- com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm

eval pn\=\${"$code"}

이는 대부분의 쉘에서 작동하는 이식 가능한 쉘 코드입니다.
Bash의 경우 다음을 사용할 수 있습니다. pn=${!code}또는 bash/ksh/zsh의 경우 다음을 사용할 수 있습니다 pn=${@:code:1}.

편지

문자(a~z 또는 A~Z)를 사용해야 하는 경우 해당 문자를 인덱스로 변환해야 합니다.

code=a                              # or A, B, C, ... etc.
set -- com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm
eval pn\=\"\${$(( ($(printf '%d' "'$code")|32)-96  ))}\"

긴 코드에서 각 부분의 의도와 의미를 명확히 합니다.

code=A

set -- com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm

asciival=$(( $(printf '%d' "'$code") ))      # byte value of the ASCII letter.
upperval=$(( asciival |  32 ))               # shift to uppercase.
indexval=$(( upperval -  96 ))               # convert to an index from a=1.
eval arg\=\"\$\{$indexval\}\"                # the argument at such index.

소문자로 변환해야 하는 경우 다음을 사용하세요( $(( asciival & ~32 ))ASCII 값의 비트 6이 설정되지 않았는지 확인하세요).

에러 코드

오류가 발생할 때 스크립트가 인쇄하는 출력은 매우 길며 매우 구체적입니다.
이를 처리하는 가장 일반적인 방법은 함수를 정의하는 것입니다.

errorcode(){ exitcode=$1; shift; printf '\a\t %s\n' "$@"; exit "$exitcode"; }

그런 다음 필요한 특정 메시지를 사용하여 함수를 호출하세요.

errorcode 27  "ERROR!" "CODE KOSONG" "MELAKUKAN EXIT OTOMATIS"

최종 종료 값은 exitcode(여기 예에서는 27)로 제공됩니다.

전체 스크립트(오류 검사 포함)는 다음과 같습니다.

errorcode(){ exitcode=$1; shift; printf '\a\t %s\n' "$@"; exit "$exitcode"; }

code=${1:-A}

case "$code" in 
    [a-d]|[A-D]) : ;;
    *)           errorcode 27  "ERROR!" "CODE KOSONG" "MELAKUKAN EXIT OTOMATIS" ;;
esac

set -- com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm
eval pn\=\"\${$(( ($(printf '%d' "'$code") & ~32) - 64  ))}\"

printf 'Code=%s Argument=%s\n' "$code" "$pn"

관련 정보