[unix] 알파벳의 ASCII 값을 가져 오는 Bash 스크립트

알파벳의 ASCII 값은 어떻게 얻습니까?

예를 들어, 97a?



답변

이 두 기능을 정의하십시오 (보통 다른 언어로 사용 가능).

chr() {
  [ "$1" -lt 256 ] || return 1
  printf "\\$(printf '%03o' "$1")"
}

ord() {
  LC_CTYPE=C printf '%d' "'$1"
}

용법:

chr 65
A

ord A
65


답변

다음을 사용하여 전체 세트를 볼 수 있습니다.

$ man ascii

8 진수, 16 진수 및 10 진수로 표를 얻을 수 있습니다.


답변

UTF-8 문자로 확장하려는 경우 :

$ perl -CA -le 'print ord shift' ?
128520

$ perl -CS -le 'print chr shift' 128520
?

bash, ksh또는 zsh내장 명령 :

$ printf "\U$(printf %08x 128520)\n"
?


답변

이것은 잘 작동합니다.

echo "A" | tr -d "\n" | od -An -t uC

echo "A"                              ### Emit a character.
         | tr -d "\n"                 ### Remove the "newline" character.
                      | od -An -t uC  ### Use od (octal dump) to print:
                                      ### -An  means Address none
                                      ### -t  select a type
                                      ###  u  type is unsigned decimal.
                                      ###  C  of size (one) char.

정확히 다음과 같습니다.

echo -n "A" | od -An -tuC        ### Not all shells honor the '-n'.


답변

간단하고 우아한 Bash 솔루션을 사용하려고합니다.

for i in {a..z}; do echo $(printf "%s %d" "$i" "'$i"); done

스크립트에서 다음을 사용할 수 있습니다.

CharValue="A"
AscValue=`printf "%d" "'$CharValue"

CharValue 앞에 작은 따옴표가 있습니다. 의무입니다 …


답변

ctbl()  for O                   in      0 1 2 3
        do  for o               in      0 1 2 3 4 5 6 7
                do for  _o      in      7 6 5 4 3 2 1 0
                        do      case    $((_o=(_o+=O*100+o*10)?_o:200)) in
                                (*00|*77) set   "${1:+ \"}\\$_o${1:-\"}";;
                                (140|42)  set   '\\'"\\$_o$1"           ;;
                                (*)       set   "\\$_o$1"               ;esac
                        done;   printf   "$1";   shift
                done
        done
eval '
ctbl(){
        ${1:+":"}       return "$((OPTARG=0))"
        set     "" ""   "${1%"${1#?}"}"
        for     c in    ${a+"a=$a"} ${b+"b=$b"} ${c+"c=$c"}\
                        ${LC_ALL+"LC_ALL=$LC_ALL"}
        do      while   case  $c in     (*\'\''*) ;; (*) ! \
                                 set "" "${c%%=*}='\''${c#*=}$1'\'' $2" "$3"
                        esac;do  set    "'"'\''\${c##*\'}"'$@";  c=${c%\'\''*}
        done;   done;   LC_ALL=C a=$3 c=;set "" "$2 OPTARG='\''${#a}*("
        while   [ 0 -ne "${#a}" ]
        do      case $a in      ([[:print:][:cntrl:]]*)
                        case    $a in   (['"$(printf \\1-\\77)"']*)
                                        b=0;;   (*)     b=1
                        esac;;  (['"$(  printf  \\200-\\277)"']*)
                                        b=2;;   (*)     b=3
                esac;    set    '"$(ctbl)"'     "$@"
                eval "   set    \"\${$((b+1))%"'\''"${a%"${a#?}"}"*}" "$6"'\''
                a=${a#?};set    "$((b=b*100+${#1}+${#1}/8*2)))" \
                                "$2(o$((c+=1))=$b)>=(d$c=$((0$b)))|"
        done;   eval "   unset   LC_ALL  a b c;${2%?})'\''"
        return  "$((${OPTARG%%\**}-1))"
}'

첫 번째 ctbl()-맨 위에는 한 번만 실행됩니다. 다음과 같은 출력을 생성합니다 ( sed -n l인쇄 성 을 위해 필터링 됨 ) .

ctbl | sed -n l

 "\200\001\002\003\004\005\006\a\b\t$
\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\
\035\036\037 !\\"#$%&'()*+,-./0123456789:;<=>?" "@ABCDEFGHIJKLMNOPQRS\
TUVWXYZ[\\]^_\\`abcdefghijklmnopqrstuvwxyz{|}~\177" "\200\201\202\203\
\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\
\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\
\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\
\267\270\271\272\273\274\275\276\277" "\300\301\302\303\304\305\306\
\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\
\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\
\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\
\372\373\374\375\376\377"$

… 모든 8 비트 바이트 (less NUL) 이며 4 개의 쉘 인용 문자열로 나뉘어 64 바이트 경계에서 균등하게 분할됩니다. 문자열은 같은 범위 진수로 표현 될 수있는 \200\1-\77, \100-\177, \200-\277, \300-\377바이트 (128)를위한 장소 홀더로서 사용된다 NUL.

ctbl()존재 의 첫 번째 목적은 문자열을 생성 eval하여 두 번째 ctbl()함수를 문자 그대로 내장 한 후에 정의하는 것입니다. 그렇게하면 필요할 때마다 다시 생성 할 필요없이 함수에서 참조 할 수 있습니다. eval두 번째 ctbl()함수를 정의 할 때 첫 번째 함수는 중단됩니다.

두 번째 ctbl()함수의 상반부 는 대부분 부수적입니다. 호출 될 때 영향을 줄 수있는 현재 쉘 상태를 이식 가능하고 안전하게 직렬화하도록 설계되었습니다. 맨 위 루프는 사용하려는 변수의 값에 따옴표를 인용 한 다음 모든 결과를 위치 매개 변수에 누적합니다.

그러나 처음 두 줄은 먼저 즉시 0을 반환 $OPTARG하고 함수의 첫 번째 인수에 하나 이상의 문자가 포함되어 있지 않으면 동일하게 설정 됩니다. 그리고 두 번째 줄은 첫 번째 인수 만 첫 번째 문자로만 잘립니다. 함수는 한 번에 한 문자 만 처리하기 때문입니다. 중요한 것은 현재 로케일 컨텍스트에서이를 수행합니다. 즉, 문자가 하나 이상의 바이트를 포함 할 수있는 경우 쉘이 멀티 바이트 문자를 올바르게 지원하는 경우에는 바이트가 아닌 문자를 제외한 모든 바이트를 버리지 않습니다. 첫 번째 인수의 첫 번째 문자.

        ${1:+":"}       return "$((OPTARG=0))"
        set     "" ""   "${1%"${1#?}"}"

그런 다음, 필요한 경우 저장 루프를 수행 한 후 LC_ALL변수 에 지정하여 모든 카테고리의 현재 로케일 컨텍스트를 C 로케일로 재정의합니다 . 이제부터 문자는 단일 바이트로만 구성 될 수 있으므로 첫 번째 인수의 첫 번째 문자에 여러 바이트가있는 경우 이제 각 문자를 개별 문자로 지정할 수 있습니다.

        LC_ALL=C

이러한 이유로 함수의 후반부 는 단일 실행 시퀀스와 달리 while 루프 입니다. 대부분의 경우 호출 당 한 번만 실행되지만, ctbl()정의 된 쉘 이 멀티 바이트 문자를 올바르게 처리하면 루프 될 수 있습니다 .

        while   [ 0 -ne "${#a}" ]
        do      case $a in      ([[:print:][:cntrl:]]*)
                        case    $a in   (['"$(printf \\1-\\77)"']*)
                                        b=0;;   (*)     b=1
                        esac;;  (['"$(  printf  \\200-\\277)"']*)
                                        b=2;;   (*)     b=3
                esac;    set    '"$(ctbl)"'     "$@"

위의 $(ctbl)명령 대체는 eval함수가 처음 정의 될 때 까지 한 번만 평가되며 해당 토큰 이후에는 쉘의 메모리에 저장된 명령 대체의 리터럴 출력으로 대체됩니다. 두 case패턴 명령 대체도 마찬가지입니다 . 이 함수는 서브 쉘이나 다른 명령을 호출하지 않습니다. 또한 버그를 나타내는 쉘 진단 메시지의 경우를 제외하고는 입출력을 읽거나 쓰려고 시도하지 않습니다 .

또한 루프 연속성에 대한 테스트는 간단하지 않습니다 [ -n "$a" ]. 왜냐하면 필자가 좌절감을 느낀 것처럼 어떤 이유로 bash쉘이 수행하기 때문입니다.

char=$(printf \\1)
[ -n "$char" ] || echo but it\'s not null\!

but it's not null!

… 따라서 $a각 반복마다 len을 0 과 명시 적으로 비교 합니다 .

case검사는 4 개의 문자열에 포함 할 첫 번째 바이트를 확인하고에 설정된 바이트에 대한 참조를 저장합니다 $b. 그 후 쉘의 첫 번째 네 개의 위치 매개 변수는 선행 문자에 의해 set포함되고 eval작성된 문자열에 대한 것 ctbl()입니다.

다음으로, 첫 번째 인수의 나머지 부분이 다시 첫 번째 문자로 일시적으로 잘립니다. 이제 단일 바이트 여야합니다. 첫 번째 바이트가 유사한 캐릭터와의 기준의 말미에서 제거하기위한 기준으로 사용된다 $b이다 eval문자열의 마지막 바이트 기준 바이트에서부터 멀리 치환 될 수 있도록 위치 파라미터를 나타내는 ‘D. 다른 세 문자열은 위치 매개 변수에서 완전히 삭제됩니다.

               eval "   set    \"\${$((b+1))%"'\''"${a%"${a#?}"}"*}" "$6"'\''
               a=${a#?};set    "$((b=b*100+${#1}+${#1}/8*2)))" \
                                "$2(o$((c+=1))=$b)>=(d$c=$((0$b)))|"

이 시점에서 바이트 값 (모듈로 64) 은 문자열의 len으로 참조 될 수 있습니다.

str=$(printf '\200\1\2\3\4\5\6\7')
ref=$(printf \\4)
str=${str%"$ref"*}
echo "${#str}"

4

그런 다음의 값을 기반으로 모듈러스를 조정하기 위해 약간의 수학이 수행되고 $b첫 번째 바이트 $a가 영구적으로 제거되고 루프 $a가 실제로 비어 있는지 확인하기 위해 현재 사이클의 출력이 완료 대기중인 스택에 추가됩니다 .

    eval "   unset   LC_ALL  a b c;${2%?})'\''"
    return  "$((${OPTARG%%\**}-1))"

경우에는 $a예외로 – 확실히 모든 이름과 상태, 비어 $OPTARG의 실행의 과정을 통해 영향을받는 기능은 이전 상태로 복원되었는지 – – 세트와 null가 아닌이 설정하고 널 (null) 또는 해제 여부 – 출력 저장 에 $OPTARG함수가 반환한다. 실제 반환 값은 첫 번째 인수의 첫 번째 문자에있는 총 바이트 수보다 1이 적습니다. 따라서 단일 바이트 문자는 0을 반환하고 모든 멀티 바이트 문자는 0보다 큰 값을 반환하므로 출력 형식이 약간 이상합니다.

ctbl()에 저장 $OPTARG평가하는 경우, 병행 형태의 변수 명을 설정 한 것을 유효한 쉘의 산술 표현식은 $o1, $d1, $o2, $d2십진수와 첫번째 인수의 선두 문자의 모든 각 바이트 진수 값하지만 결국 총 평가 첫 번째 인수의 바이트 수 이 글을 쓸 때 특정 종류의 워크 플로를 염두에 두었고 시연이 좋을 것 같습니다.

종종 getopts다음 과 같이 문자열을 분리 해야하는 이유를 찾습니다 .

str=some\ string OPTIND=1
while   getopts : na  -"$str"
do      printf %s\\n "$OPTARG"
done

s
o
m
e

s
t
r
i
n
g

아마 한 줄에 문자를 인쇄하는 것보다 조금 더 할 것이지만 가능합니다. 어떤 경우에, 나는 아직 발견되지 않은 getopts제대로 할 것을 – (저를 공격 dash의는 getopts이 문자로 숯불 않지만, bash확실히하지 않습니다) :

str=ŐőŒœŔŕŖŗŘřŚśŜŝŞş  OPTIND=1
while   getopts : na  -"$str"
do      printf %s\\n "$OPTARG"
done|   od -tc

0000000 305  \n 220  \n 305  \n 221  \n 305  \n 222  \n 305  \n 223  \n
0000020 305  \n 224  \n 305  \n 225  \n 305  \n 226  \n 305  \n 227  \n
0000040 305  \n 230  \n 305  \n 231  \n 305  \n 232  \n 305  \n 233  \n
0000060 305  \n 234  \n 305  \n 235  \n 305  \n 236  \n 305  \n 237  \n
0000100

승인. 그래서 시도했습니다 …

str=ŐőŒœŔŕŖŗŘřŚśŜŝŞş
while   [ 0 -ne "${#str}" ]
do      printf %c\\n "$str"    #identical results for %.1s
        str=${str#?}
done|   od -tc

#dash
0000000 305  \n 220  \n 305  \n 221  \n 305  \n 222  \n 305  \n 223  \n
0000020 305  \n 224  \n 305  \n 225  \n 305  \n 226  \n 305  \n 227  \n
0000040 305  \n 230  \n 305  \n 231  \n 305  \n 232  \n 305  \n 233  \n
0000060 305  \n 234  \n 305  \n 235  \n 305  \n 236  \n 305  \n 237  \n
0000100

#bash
0000000 305  \n 305  \n 305  \n 305  \n 305  \n 305  \n 305  \n 305  \n
*
0000040

그런 종류의 워크 플로우-char 종류의 byte / char 바이트는 tty 작업을 할 때 자주 사용되는 워크 플로우입니다. 입력의 최첨단에서는 문자 값을 읽 자마자 알아야하며 크기 (특히 열을 계산할 때) 가 필요하며 문자가 전체 문자 가되어야 합니다.

그리고 지금은 ctbl():

str=ŐőŒœŔŕŖŗŘřŚśŜŝŞş
while [ 0 -ne "${#str}" ]
do    ctbl "$str"
      printf "%.$(($OPTARG))s\t::\t$OPTARG\t::\t$?\t::\t\\$o1\\$o2\n" "$str"
      str=${str#?}
done

Ő   ::  2*((o1=305)>=(d1=197)|(o2=220)>=(d2=144))   ::  1   ::  Ő
ő   ::  2*((o1=305)>=(d1=197)|(o2=221)>=(d2=145))   ::  1   ::  ő
Œ   ::  2*((o1=305)>=(d1=197)|(o2=222)>=(d2=146))   ::  1   ::  Œ
œ   ::  2*((o1=305)>=(d1=197)|(o2=223)>=(d2=147))   ::  1   ::  œ
Ŕ   ::  2*((o1=305)>=(d1=197)|(o2=224)>=(d2=148))   ::  1   ::  Ŕ
ŕ   ::  2*((o1=305)>=(d1=197)|(o2=225)>=(d2=149))   ::  1   ::  ŕ
Ŗ   ::  2*((o1=305)>=(d1=197)|(o2=226)>=(d2=150))   ::  1   ::  Ŗ
ŗ   ::  2*((o1=305)>=(d1=197)|(o2=227)>=(d2=151))   ::  1   ::  ŗ
Ř   ::  2*((o1=305)>=(d1=197)|(o2=230)>=(d2=152))   ::  1   ::  Ř
ř   ::  2*((o1=305)>=(d1=197)|(o2=231)>=(d2=153))   ::  1   ::  ř
Ś   ::  2*((o1=305)>=(d1=197)|(o2=232)>=(d2=154))   ::  1   ::  Ś
ś   ::  2*((o1=305)>=(d1=197)|(o2=233)>=(d2=155))   ::  1   ::  ś
Ŝ   ::  2*((o1=305)>=(d1=197)|(o2=234)>=(d2=156))   ::  1   ::  Ŝ
ŝ   ::  2*((o1=305)>=(d1=197)|(o2=235)>=(d2=157))   ::  1   ::  ŝ
Ş   ::  2*((o1=305)>=(d1=197)|(o2=236)>=(d2=158))   ::  1   ::  Ş
ş   ::  2*((o1=305)>=(d1=197)|(o2=237)>=(d2=159))   ::  1   ::  ş

참고 ctbl()실제로 정의하지 않습니다 $[od][12...]이 어떤 상태에 어떤 지속적인 영향을 미치지 않습니다하지만 결코 – 변수 $OPTARG-하지만이의 문자열을두고 $OPTARG사용할 수 있습니다 위의 수행하여 내가 각 문자의 두 번째 사본을 얻을 방법이다 -을 정의 할 수 printf "\\$o1\\$o2"있기 때문에 내가 평가할 때마다 설정됩니다 $(($OPTARG)). 하지만 그것을 어디에 나 또한 필드 길이 수정을 선언하고있어 printf‘의 %s캐릭터 라인의 인수 형식과 표현이 항상 문자 바이트의 총 숫자로 평가하기 때문에 내가 할 때, 나는 출력에 전체 문자를 얻을 :

printf %.2s "$str"


답변

쉘 스크립트는 아니지만 작동

awk 'BEGIN{for( i=97; i<=122;i++) printf "%c %d\n",i,i }'  

샘플 출력

xieerqi:$ awk 'BEGIN{for( i=97; i<=122;i++) printf "%c %d\n",i,i }' | head -n 5
a 97
b 98
c 99
d 100
e 101