이 쉘 스크립트를 어떻게 단축 할 수 있습니까?
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
답변
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
리디렉션이 작업을 수행합니다. 또한 스크립트 (또는 프로그램)가 실패하면 0이 아닌 상태 ( exit 1
) 로 종료하는 것이 가장 좋으므로 호출 컨텍스트는 무엇이 잘못되었는지 알 수 있습니다. 다른 상태를 사용하여 다른 문제를 나타낼 수도 있습니다 ( 좋은 예 는 curl
매뉴얼 페이지 의 “EXIT CODES”섹션 참조 ). (여기에 대한 제안은 Stéphane Chazelas와 Monty Harder에게 감사드립니다.)
OS, 버전, 설정 등 사이에서 이식성이 뛰어 나기 때문에 (및 ) printf
대신을 추천 합니다 . OS 업데이트에 다른 옵션으로 컴파일 된 bash 버전이 포함되어있어 동작 방식이 변경되어 스크립트가 중단되었습니다 .echo -e
echo -n
echo
여기에 큰 따옴표 $CODE
는 필요하지 않습니다. 의 문자열은 case
안전하지 않은 몇 가지 컨텍스트 중 하나입니다. 그러나 안전하지 않은 곳과 그렇지 않은 곳을 추적하기가 어렵 기 때문에 변수 참조를 큰 따옴표로 묶는 것을 선호합니다. 따라서 습관적으로 큰 따옴표로 묶는 것이 더 안전합니다.
답변
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
만 소문자로 전환)이 배열을하지만,이 경우 $CODE
에 유효한 항목에 해당하지 않는 domain
목록, 그것은으로 스크립트를 종료 오류.
${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
배열 에 소문자 키가 존재하는 경우).
경우 $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}
답변
쉘이 배열을 허용한다면 가장 짧은 대답은 bash의 다음 예와 같아야합니다.
declare -A site
site=( [a]=com.tencent.ig [b]=com.vng.pubgmobile [c]=com.pubg.krmobile [d]=com.rekoo.pubgm )
pn=${site[${code,}]}
그것은 $code
a, 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
답변
이 답변을 다른 방향으로 가져 가겠습니다. 데이터를 스크립트로 코딩하는 대신 해당 데이터를 별도의 데이터 파일에 넣은 다음 코드를 사용하여 파일을 검색하십시오.
$ cat names.cfg
a com.tencent.ig
b com.vng.pubgmobile
c com.pubg.krmobile
d com.rekoo.pubgm
$ cat lookup.sh
PN=$(awk -v code="${1:-}" 'tolower($1) == tolower(code) { print $2; }' names.cfg)
if [ -z "${PN}" ]; then
printf '\a\t%s\n' 'ERROR!' 'CODE KOSONG' 'MELAKUKAN EXIT OTOMATIS' >&2
exit 1
fi
echo "${PN}"
$ bash lookup.sh A
com.tencent.ig
$ bash lookup.sh a
com.tencent.ig
$ bash lookup.sh x
ERROR!
CODE KOSONG
MELAKUKAN EXIT OTOMATIS
이러한 우려를 분리하면 몇 가지 이점이 있습니다.
- 코드 논리를 해결하지 않고도 쉽고 간단하게 데이터를 추가 및 제거 할 수 있습니다.
- 특정 하위 도메인에있는 일치 항목 수를 계산하는 등 다른 프로그램에서 데이터를 재사용 할 수 있습니다.
- 당신이있는 경우 큰 데이터의 목록을, 당신은 디스크 사용에 정렬 할 수 있습니다
look
효율적 이진 검색이 (가 아닌 라인 라인에 의해grep
또는awk
)
답변
문자를 사용하여 값을 인덱싱하고 숫자를 사용하는 경우 다음과 같이 간단 해집니다.
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 ))
(아스키 값의 비트 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"