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


48

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

例えば、97のためにa

回答:


70

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

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です。これらはprintfに渡されます。printfコンテキストでは、AのASCII値に変換され、最終的に印刷されます10進数のおかげで'%d'。を使用'Ox%x'してヘキサで表示したり'0%o'、8進数で表示したりします))
オリビエデュラック

3
D、しかし真剣にこれらを何:-1、それがどのように動作するか...冗談説明ではないためprintf "\\$(printf '%03o' "$1")"'%03o'LC_CTYPE=C及びで単一引用符"'$1"のですか?
ラザック14

1
FAQ 71の詳細をすべてお読みください。優れた詳細分析。

19

セット全体を見るには:

$ man ascii

テーブルは8進数、16進数、10進数で取得できます。


debianベースのディストリビューション用のasciiパッケージもありますが、(少なくとも今のところ)質問はbashとしてタグ付けされているため、これらはOPを助けません。実際、それは私のシステムにインストールされており、man asciiから得られるのはそのmanページだけです。
ジョー

12

UTF-8文字に拡張する場合:

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

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

または組み込みコマンド:bashkshzsh

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

四角いボックス文字を配置するつもりでしたか、そうでなければ元の文字が投稿に表示されず、四角いボックス文字に置き換えられます。
mtk

1
@ mtk、UTF-8を表示するブラウザと、128520文字のフォントが必要です。
ステファンシャゼル

私は最新のChromeを使用していますが、UTF-8をサポートしていないとは思いません。使用しているブラウザを知りたいですか?
mtk

@mtk、iceweaselオンDebian sid。iceweaselのWebコンソールによって確認されるようフォントは「そしてDejaVuなき」であると私が、上流でのDebianから来るインストールTTF-そしてDejaVu TTF-そしてDejaVuコアTTF-そしてDejaVu-追加パッケージ持って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
簡単な説明を追加できますか?
ベルンハルト

入力から "\ n"(改行)を削除するtr。odは-tに使用され、dCは小数点文字で出力します。
サラバナン

1
echo -nの必要性を排除する後続の改行を抑制するtr -d "\n"
Gowtham

2
@Gowtham、の一部の実装のみでecho、たとえばUnix準拠のエコーではありません。printf %s Aポータブルなものになります。
ステファンシャゼル

6

私はシンプルな(そしてエレガントな?)Bashソリューションに行きます:

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

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

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

CharValueの前の単一引用符に注意してください。義務付けられています...


1
あなたの答えはdsmsk80の答えとどう違うのですか?
ベルンハルト

1
私の質問の解釈は、「アルファベットの値のASCII値を取得する方法」です。1文字のASCII値を取得する関数を定義する方法ではありません。したがって、私の最初の答えは、アルファベットのASCII値を取得する短い1行のコマンドです。
-phulstaert

私はあなたのポイントを得るが、私はまだ両方の答えの一番下の行があると思いますprintf "%d"
ベルンハルト

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ビットバイト(より小さいNUL)で、シェルで引用された4つの文字列に分割され、64バイト境界で均等に分割されます。文字列は次のように進範囲で表現されるかもしれない\200\1-\77\100-\177\200-\277\300-\377バイト128は、のプレースホルダーとして使用されています、NUL

最初ctbl()のの存在の全体的な目的は、それらの文字列を生成することです。それにより、文字列が埋め込まれた後のeval2番目のctbl()関数を定義できます。そのようにして、必要なたびに再生成することなく、関数内で参照できます。ときにeval二定義しないctbl()機能を最初はできなくなります。

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

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

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

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

        LC_ALL=C

このため、関数の後半は、単独で実行されるシーケンスではなく、while ループです。ほとんどの場合、おそらく呼び出しごとに1回だけ実行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、関数が最初に定義されるまでに一度だけ評価され、そのトークンがシェルのメモリに保存されたそのコマンド置換のリテラル出力で永久に置き換えられることに注意してください。2つのcaseパターンコマンドの置換についても同じことが言えます。この関数は、サブシェルやその他のコマンドを呼び出すことはありません。また、入出力を読み書きしようとすることもありません(シェル診断メッセージの場合を除き、これはおそらくバグを示しています)

また、ループの連続性のテストは単純[ -n "$a" ]ではないことに注意してください。これは、フラストレーションに気づいたように、何らかの理由でbashシェルが行うためです。

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

but it's not null!

...と私は明示的に比較するので$a、の各反復のために0にlenをこれ、異なっまたどういうわけか、振る舞う(読み:正しく)

caseチェック私たちの4つの文字列と店でバイトのセットへの参照のいずれかに含めるための最初のバイト$b。その後、シェルの最初の4つの位置パラメータはset、の前者によって埋め込まれeval、書き込まれた文字列になりますctbl()

次に、最初の引数に残っているものはすべて、再び最初の文字に一時的に切り捨てられます。これは、1バイトであることが保証されるはずです。この最初のバイトは、それがマッチした文字列と参照の尾からストリップへの参照として使用され$bているeval文字列の最後のバイトへの参照バイトからすべてが離れて置換することができるので、位置パラメータを表すために、D」。他の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

次に、値inに基づいてモジュラスを調整するために少しの計算が行われ$b、最初のバイトin $aは永久に取り除かれ、現在のサイクルの出力は、$a実際に空かどうかを確認するためにループがリサイクルされる前にスタックに追加されます。

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

とき$aを除いては-確かに、すべての名前や状態空で$OPTARG集合していないヌル、セットとヌル、または設定解除するかどうか- -その実行の過程を通じて影響を受ける機能は、以前の状態に復元されていることを-と出力が保存されますto $OPTARG関数が戻るとき。実際の戻り値は、最初の引数の最初の文字の合計バイト数よりも1つ少ないため、1バイト文字はゼロを返し、マルチバイト文字はゼロを超える値を返します。その出力形式は少し奇妙です。

値が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

おそらく、1行に1文字ずつ出力するだけではありませんが、何でも可能です。いずれにせよ、私はまだ見つかっていないgetopts適切に行いますこと(というスト- dashgetoptsそれはcharでchar型、しかしん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

そのようなワークフロー-byteのbyte / charのchar-は、ttyをやるときによく使うワークフローです。入力のリーディングエッジでは、char値を読み取るとすぐに知る必要があり、そのサイズ(特に列をカウントする場合)が必要です。また文字全体を文字にする必要があります。

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

printf %.2s "$str"

難読化されたbashコードコンテストに参加する必要があります。
HelloGoodbye

1
@HelloGoodbyeこれはbashコードではありません。これも難読化されていません。難読化を確認するには、[ "$(printf \\1)" ]|| ! echo but its not null!その間を参照してください。実際にそのようなコンテストを推奨しない限り、意味のあるコメントの実践を自由に理解してください。
mikeserv

いいえ、そうではありません。私が書いたのは、あなたのコードが非常に混乱しているという別の言い方です(少なくとも私には)。bashではない場合、どの言語ですか?
HelloGoodbye

@HelloGoodbye-これはPOSIX shコマンド言語です。bash再びボーン同じでsuprasetは、広くポータブルに向かって上に与えられるケアの多くのための大部分の急激な動機、自己が拡大し、あらゆる種類の名誉文字サイズを名前空間。bashこれの多くをすでに処理する必要がありcますprintfが、言語は上記の機能を提供していませんでした。
mikeserv

単純さと読みやすさのために、私はまだprintf "%d" "'$ char"を使用する傾向があります。@mikeservのソリューションが対処する問題にどのような問題が私をさらすのか興味がありますか?リターンコードに影響を与える制御文字(上記のコメントで彼のポイントだったと思う)だけではありませんか?
アレックスヤンセン

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.