回答:
これらの2つの関数を定義します(通常は他の言語で利用可能です):
chr() {
[ "$1" -lt 256 ] || return 1
printf "\\$(printf '%03o' "$1")"
}
ord() {
LC_CTYPE=C printf '%d' "'$1"
}
使用法:
chr 65
A
ord A
65
printf "\\$(printf '%03o' "$1")"
、'%03o'
、LC_CTYPE=C
及びで単一引用符"'$1"
のですか?
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"
😈
iceweasel
オンDebian sid
。iceweaselのWebコンソールによって確認されるようフォントは「そしてDejaVuなき」であると私が、上流でのDebianから来るインストールTTF-そしてDejaVu TTF-そしてDejaVuコアTTF-そしてDejaVu-追加パッケージ持ってdejavu-fonts.orgを
これはうまく機能し、
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'.
echo -n
の必要性を排除する後続の改行を抑制するtr -d "\n"
echo
、たとえばUnix準拠のエコーではありません。printf %s A
ポータブルなものになります。
私はシンプルな(そしてエレガントな?)Bashソリューションに行きます:
for i in {a..z}; do echo $(printf "%s %d" "$i" "'$i"); done
スクリプトでは、次を使用できます。
CharValue="A"
AscValue=`printf "%d" "'$CharValue"
CharValueの前の単一引用符に注意してください。義務付けられています...
printf "%d"
。
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()
のの存在の全体的な目的は、それらの文字列を生成することです。それにより、文字列が埋め込まれた後のeval
2番目の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
適切に行いますこと(というスト- dash
のgetopts
それは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"
[ "$(printf \\1)" ]|| ! echo but its not null!
その間を参照してください。実際にそのようなコンテストを推奨しない限り、意味のあるコメントの実践を自由に理解してください。
sh
コマンド言語です。bash
で再びボーン同じでsuprasetは、広くポータブルに向かって上に与えられるケアの多くのための大部分の急激な動機、自己が拡大し、あらゆる種類の名誉文字サイズを名前空間。bash
これの多くをすでに処理する必要がありc
ますprintf
が、言語は上記の機能を提供していませんでした。
シェルスクリプトではありませんが、動作します
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
"'A"
あなたが"A"
それを使うならそれは言うでしょうが正しいですA: invalid number
。それはprintf側で行われたようです(つまり、シェルで"'A"
は、実際に2文字、a'
とaA
です。これらはprintfに渡されます。printfコンテキストでは、AのASCII値に変換され、最終的に印刷されます10進数のおかげで'%d'
。を使用'Ox%x'
してヘキサで表示したり'0%o'
、8進数で表示したりします))