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


답변:


69

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

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

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

용법:

chr 65
A

ord A
65

7
@ dmsk80 : +1 나 같은 사람들이 오타를 발견했다고 생각 "'A"하는 경우 : 맞지만, 사용하면 다음과 같이 "A"말할 수 있습니다 A: invalid number. 그것은 printf면에서 수행 된 것처럼 보입니다 (즉, 쉘에서 "'A"실제로 2 개의 문자 a '와 a A입니다. 받는 소수 감사로 '%d'사용합니다. 'Ox%x'헥사에이를 표시하거나 '0%o'8 진수로 그것을 가지고))
올리비에 Dulac

3
위해를 -1은 농담 ... 어떻게 작동하는지 설명하지 : D를하지만, 진지하게 이런 일을 printf "\\$(printf '%03o' "$1")", '%03o', LC_CTYPE=C과에서 따옴표 "'$1"합니까?
razzak

1
FAQ 71의 모든 세부 사항을 읽으십시오 . 탁월한 상세 분석.

19

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

$ man ascii

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


데비안 기반 배포판을위한 ascii 패키지도 있지만 (최소한 현재) 질문은 bash로 태그가 지정되어 있으므로 OP에 도움이되지 않습니다. 사실, 그것은 내 시스템에 설치되어 있으며 man ascii에서 얻는 모든 것은 맨 페이지입니다.
Joe

12

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"
😈

사각형 상자 문자를 넣으려고 했습니까? 그렇지 않으면 원래 문자가 게시물에 표시되지 않고 사각형 상자 문자로 대체됩니다.
mtk

1
@mtk, UTF-8을 표시하는 브라우저와 해당 128520 문자 의 글꼴이 필요 합니다.
Stéphane Chazelas

최신 Chrome을 사용하고 있으며 UTF-8을 지원하지 않는다고 생각하지 않습니다. 현재 사용중인 브라우저를 알고 싶으십니까?
mtk

@mtk, iceweaselDebian sid. iceweasel의 웹 콘솔에서 확인 된 글꼴은 "같은데요 산세"내가에서 상류로 데비안에서 온 설치 TTF-데자뷰 TTF-데자뷰 코어 TTF-데자뷰 - 추가 패키지있어 dejavu-fonts.org을
스테판 Chazelas가

128520의 기본은 무엇입니까? 내 자신 ctbl()이 올바르게 표시하고 문자열 머리에서 문자를 슬라이스 하여 바이트 값을 printf넣을 수 4*((o1=360)>=(d1=240)|(o2=237)>=(d2=159)|(o3=230)>=(d3=152)|(o4=210)>=(d4=136))있는 것처럼 보입니다 $OPTARG.
mikeserv

12

이것은 잘 작동합니다.

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'.

3
작은 설명을 추가 할 수 있습니까?
Bernhard

tr을 입력에서 "\ n"(새 줄)을 제거합니다. od는 -t에 사용됩니다. dC는 10 진수 문자로 인쇄합니다.
Saravanan

1
echo -n에 대한 필요성을 없애 줄 바꿈 후행 억제합니다tr -d "\n"
Gowtham

2
@Gowtham echo은 유닉스 호환 반향이 아닌 일부 구현 만 가능 합니다. printf %s A휴대용 것입니다.
Stéphane Chazelas

6

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

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

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

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

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


1
답변이 dsmsk80의 답변과 어떻게 다릅니 까?
Bernhard

1
질문에 대한 나의 해석은 "알파벳 값의 ASCII 값을 얻는 방법"입니다. 한 문자의 ASCII 값을 검색하는 함수를 정의하는 방법이 아닙니다. 그래서 첫 번째 대답은 알파벳의 ASCII 값을 얻는 간단한 한 줄 명령입니다.
phulstaert

나는 당신의 요점을 얻었지만 여전히 두 대답의 결론은 printf "%d"입니다.
Bernhard

2
나는 이것이 결과를 얻는 과정의 중요한 부분이라는 데 동의하지만, xmpirate가 "for i in"과 범위 사용에 대해 알고 있다고 가정하고 싶지 않았습니다. 만약 그가리스트를 원한다면 이것은 시간을 절약 해 줄 수있다. ;-). 또한 장래 독자들은 내 추가 내용이 도움이 될 수 있습니다.
phulstaert

6
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"

난독 화 된 bash 코드 컨테스트에서 경쟁해야합니다!
HelloGoodbye

1
@HelloGoodbye 이것은 bash 코드가 아닙니다 . 이것도 난독 화되지도 않습니다. 난독을보고자 [ "$(printf \\1)" ]|| ! echo but its not null!한다면 실제 대회를 추천하지 않는 한, 의미있는 의견 연습에 익숙해 지도록 자유롭게 참고하십시오 .
mikeserv

아니요, 필자가 작성 한 내용은 코드가 매우 혼란 스럽지만 (적어도 나에게는) 혼란 스러울 수있는 또 다른 방법 일뿐이지만 쉽게 이해할 수는 없었습니다. 배쉬가 아니라면 어떤 언어입니까?
HelloGoodbye

@HelloGoodbye-POSIX sh명령 언어입니다. bash본은 다시 동일 하게 상복 된 본이며, 대체로 휴대가 용이하고 자체 확장되며 모든 종류의 명목상의 캐릭터 크기를 향한 많은 관심에 대한 강력한 동기 부여입니다. bash이 중 많은 부분을 이미 처리해야하지만 c언어 printf는 위의 기능이 부족했을 수도 있습니다.
mikeserv

저는 단순성과 가독성을 위해 printf "% d" " '$ char"를 사용하려고합니다. 이것이 @mikeserv의 솔루션 주소에 어떤 종류의 문제가 노출되는지 궁금합니다. 리턴 코드에 영향을 미치는 제어 문자 이상이 있습니까? (위의 주석에서 그의 요점이라고 생각합니다)?
Alex Jansen

3

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

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

2
  • 기호를 선택한 다음 Ctrl + C를 누릅니다.
  • 열다 konsole
  • 그리고 입력 : xxd<press enter>
  • 그런 다음 <SHIFT+INSERT><CTRL+D>

당신은 다음과 같은 것을 얻습니다 :

mariank@dd903c5n1 ~ $ xxd
û0000000: fb 

붙여 넣은 기호에 16 진 코드가 있다는 것을 알고 있습니다. 0xfb

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.