web-dev-qa-db-ja.com

ASCIIアルファベットの値を取得するためのBashスクリプト

アルファベットのASCII=値を取得するにはどうすればよいですか?

例えば、 97 for a

53
xmpirate

次の2つの関数を定義します(通常、他の言語で利用可能):

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

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

使用法:

chr 65
A

ord A
65
76
dsmsk80

セット全体を見るには:

$ man ascii

8進数、16進数、10進数のテーブルが表示されます。

20
ford

これはうまく機能し、

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

これをUTF-8文字に拡張する場合(UTF-8ロケールを使用していると想定):

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

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

bashkshまたはzshビルトインの場合:

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

シンプルな(そしてエレガントな?)Bashソリューションを使用します。

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

スクリプトでは、次を使用できます。

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

CharValueの前の単一引用符に注意してください。それは義務です...

6
phulstaert
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が2番目のctbl()関数を定義し、その後に文字通り埋め込まれるようにすることです。このようにして、必要になるたびに再度生成する必要なく、関数内でそれらを参照できます。 evalが2番目のctbl()関数を定義すると、最初の関数は終了します。

2番目のctbl()関数の上半分は、ほとんどの場合、ここでは補助的なものです。呼び出されたときに影響する可能性のある現在のシェル状態を移植可能かつ安全にシリアル化するように設計されています。上のループは、使用する可能性のある変数の値の引用符を引用し、すべての結果をその位置パラメーターにスタックします。

ただし、最初の2行は最初にすぐに0を返し、関数の最初の引数に少なくとも1つの文字が含まれていない場合は$OPTARGを同じに設定します。その場合、関数は一度に1文字しか処理しないため、2行目は最初の引数を最初の文字のみにすぐに切り捨てます。重要なのは、現在のロケールコンテキストでこれを行うことです。つまり、文字が1バイトを超える可能性がある場合、シェルがマルチバイト文字を適切にサポートしていれば、それ以外のバイトは破棄されません。最初の引数の最初の文字。

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

次に、必要に応じて保存ループを実行し、その後、LC_ALL変数に割り当てることにより、現在のロケールコンテキストをすべてのカテゴリのCロケールに再定義します。この時点から、文字は1バイトのみで構成できるため、最初の引数の最初の文字に複数のバイトがあった場合、これらの文字はそれぞれが個別の文字としてアドレス指定できるはずです。

        LC_ALL=C

このため、関数の後半は、単独で実行されるシーケンスとは対照的に、while loop です。ほとんどの場合、呼び出しごとに1回だけ実行されますが、ctbl()が定義されているシェルがマルチバイト文字を適切に処理する場合、 might ループします。

        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によって1回だけ評価され、そのトークンがシェルのメモリに保存されたコマンド置換のリテラル出力でいつまでも置き換えられることに注意してください。 。 2つの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に格納します。その後、シェルの最初の4つの位置パラメータは、setによって埋め込まれた文字列に対するevalであり、ctbl()の前身によって書き込まれました。

次に、最初の引数に残っているものはすべて一時的に最初の文字に切り捨てられます。これで、1バイトになることが保証されます。この最初のバイトは、一致した文字列の末尾から削除するための参照として使用され、$bの参照は、位置パラメータを表すevalとして、文字列の参照バイトから最後のバイトまでのすべてを置き換えることができます。他の3つの文字列は、位置パラメータから完全に削除されます。

               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でもありません、setおよびnull、またはunset-関数が戻ると、出力は$OPTARGに保存されます。実際の戻り値は、最初の引数の最初の文字の合計バイト数より1少ないため、シングルバイト文字はゼロを返し、マルチバイト文字はゼロより大きい値を返します。その出力形式は少し変わっています。

ctbl()$OPTARGに保存する値は、有効なシェル算術式であり、評価されると、フォームの変数名$o1$d1を同時に設定します$o2$d2を、最初の引数の最初の文字のそれぞれのバイトの10進数と8進数の値に最終的に、最初の引数の合計バイト数に評価されます。これを書いているとき、私は特定の種類のワークフローを念頭に置いていましたが、おそらくデモが適切だと思います。

私はよく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

おそらく、1行に1文字ずつ出力するだけではありませんが、何でも可能です。いずれにせよ、適切に機能するgetoptsをまだ見つけていません(ストライク-dashgetoptsは文字単位で実行しますが、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

OK。だから私は試しました...

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

その種類のワークフロー(バイト単位のバイト/文字単位の文字)は、ttyを行うときによく利用するワークフローです。入力のリーディングエッジでは、charの値を読んだらすぐに知る必要があり、charのサイズが必要です(特に列をカウントする場合)、そして文字が whole 文字。

そして今私は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に入れますそれらを定義する-これは、$(($OPTARG))を評価するたびに設定されるため、printf "\\$o1\\$o2"を実行して上記の各文字の2番目のコピーを取得する方法です。しかし、それを行う場所では、フィールド長修飾子をprintf%s文字列引数形式に宣言しています。また、式は常に文字の合計バイト数に評価されるため、出力時に文字全体を取得します。

printf %.2s "$str"
6
mikeserv
  • 記号を選択し、CTRL + Cを押す
  • 開くkonsole
  • と入力:xxd<press enter>
  • 次に<SHIFT+INSERT><CTRL+D>を押します

あなたは次のようなものを得ます:

mariank@dd903c5n1 ~ $ xxd
û0000000: fb 

貼り付けたシンボルが16進コード0xfbであることがわかります

3
Marian Klen

シェルスクリプトではありませんが、動作します

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
3