前回、改行コードを扱ったときに、 Bash で CR の改行コードをファイルに書き込むことを調べたので、書いておきます。
結果だけ知りたい場合は、 ASCII 文字の一覧をご参照ください。
環境
- Ubuntu 16.04 LTS
echo
echo
コマンドでできるかな、と思って man echo
を調べてみました。
-n do not output the trailing newline
-e enable interpretation of backslash escapes
If -e is in effect, the following sequences are recognized:
\n new line
\r carriage return
man echo
$ echo -ne '\r' | od -t a
0000000 cr
0000001
CR はエスケープ文字で \r
のように記述すると出力できます。
バックスラッシュのエスケープ文字を有効にするには -e
のオプションをつけるようです。
-n
オプションをつけると出力の最後で改行しないようです。
octal value
\0NNN byte with octal value NNN (1 to 3 digits)
man echo
今回は、 ASCII 文字の一覧を表示したいので、コードで文字を指定する方法を調べてみました。
8 進数で指定する場合は、 \0NNN
のように記述するようです。
$ echo -e '\0101'
A
8 進数の 101 は A なので、 A と表示されました。
$ echo -ne '\015' | od -t a
0000000 cr
0000001
8 進数の 15 は CR なので、 CR と表示されました。
hexadecimal value
\xHH byte with hexadecimal value HH (1 to 2 digits)
man echo
16 進数で指定する場合は、 \xHH
のように記述するようです。
$ echo -e '\x42'
B
16 進数の 42 は B なので、 B と表示されました。
$ echo -ne '\x0d' | od -t a
0000000 cr
0000001
16 進数の 0d は CR なので、 CR と表示されました。
man echo
を見ると、 10 進数では指定できないようで、 10 進数を 8 進数か 16 進数に変換する必要があるようでした。
printf
Convert a decimal number to Hex
printf "0x%X\n " 15 # 0xF
Convert a decimal number to Octal
printf "0%o\n " 8 # 010
調べてみると、 10 進数から 8 進数や 16 進数に変換するには、 printf
を使うのが多いみたいでした。
それ以外だと簡単にはできないのかな。
WSL の Ubuntu の man printf
には Convert a decimal number to Hex や Convert a decimal number to Octal の記載がなかったので、ウェブサイトから引用しました。
Convert a decimal number to Octal
10 進数から 8 進数にしてみます。
$ printf "0%o\n " 8
010
8 進数にできました。 10 進数の 8 は 8 進数の 10 です。
Convert a decimal number to Hex
10 進数から 16 進数にしてみます。
$ printf "0x%X\n " 15
0xF
16 進数にできました。 10 進数の 15 は 16 進数の F です。
Command substitution
10 進数から 8 進数や 16 進数にした結果を別のコマンドの入力にしたかったのですが、 echo
や printf
は標準入力から入力できないみたいでした。
Command substitution allows the output of a command to replace the command itself. Command substitution occurs when a command is enclosed as follows:
$(command)
or
`command`
$(command)
は Command substitution というそうです。
コマンドの結果を返して変数に代入するときとかに使うようです。
`command`
と記述しても同じ意味になるようです。
Command substitution を使って、 command "$(printf ...)"
のようにしてみます。
printf byte
echo
でもコードから ASCII 文字を出力することができましたが、 printf
でもできるみたいでした。
10 進数から 8 進数や 16 進数にするのに printf
を使うので、統一して printf
で ASCII 文字を出力しようと思います。
printf octal value
FORMAT controls the output as in C printf. Interpreted sequences are:
\NNN byte with octal value NNN (1 to 3 digits)
man printf
printf
で 8 進数から ASCII 文字を表示するには、 \NNN
という書式を設定すればいいみたいです。
NNN
のところを 10 進数で指定して、 8 進数に変換した結果を渡したいので、 Command substitution も使って、次のように記述しました。
$ printf "$(printf '\\%o' 65)"
A
内側の printf
で 10 進数から 8 進数に変換した結果を返しました。
書式の先頭に \\
をつけましたので、 \NNN
の結果を返すことになります。
外側の printf
で 8 進数のコードから ASCII 文字を表示することになります。
10 進数の 65 は A なので、 A と表示されました。
printf hexadecimal value
FORMAT controls the output as in C printf. Interpreted sequences are:
\xHH byte with hexadecimal value HH (1 to 2 digits)
man printf
printf
で 16 進数から ASCII 文字を表示するには、 \xHH
という書式を設定すればいいみたいです。
HH
のところを 10 進数で指定して、 16 進数に変換した結果を渡したいので、 Command substitution も使って、次のように記述しました。
$ printf "$(printf '\\x%x' 66)"
B
10 進数の 66 は B なので、 B と表示されました。
'\\x%x'
のところ、ダブルクォーテーションだったり、 \
が 1 つだったりするとエラーになりました。
シングルクォーテーションで、 \\
のようにしておく必要があるようでした。
$ printf "\\x%x" 65
-bash: printf: missing hex digit for \x
\x41
$ printf '\x%x' 65
-bash: printf: missing hex digit for \x
\x41
たぶん、 printf
は引数を 1 つだけとって、 \xHH
のように記述することもできるので、
$ printf "\x41"
A
%x
の書式に引数の値を入れるよりも先に、 \xHH
の解釈をしようとしてエラーになってしまっているように見えました。
Brace Expansion
1 つの 10 進数から ASCII 文字を表示するところまでできました。 一覧を表示したいので、これを繰り返し処理してみたいと思います。
ASCIIとは、アルファベットや数字、記号などを収録した文字コードの一つ。最も基本的な文字コードとして世界的に普及している。7ビットの整数(0~127)で表現され、ラテンアルファベット(ローマ字)、数字、記号、空白文字、制御文字など128文字を収録している。
現代のコンピュータのほとんどは1バイト(8ビット)を単位としてデータを扱うため、1文字を7ビットではなく1バイトで表すのが都合がよく、その際、128から255までの128文字分はASCIIでは規定されていない領域となる。
ASCII 文字は 10 進数で表現すると 0 から 127 までになります。 まず、 10 進数で 0 から 127 を表示してみます。
Brace expansion is a mechanism by which arbitrary strings may be generated.
…略…
Brace expansions may be nested. The results of each expanded string are not sorted; left to right order is preserved. For example,
bash$ echo a{d,c,b}e ade ace abe
A sequence expression takes the form {x..y[..incr]}, where x and y are either integers or single characters, and incr, an optional increment, is an integer.
ブレース展開というものがあるようです。 引用の例ではカンマで区切られた文字列を記述していますが、シーケンス式で連番を返すこともできるようです。
$ echo {1..10}
1 2 3 4 5 6 7 8 9 10
英字もいけます。
$ echo {A..E}
A B C D E
printf
もいけます。
$ printf "%o\n" {1..10}
1
2
3
…略…
7
10
11
12
ここでは 8 進数で表示してみました。
printf
の引数でブレース展開をして、繰り返し printf
コマンドを実行できるのは初めて知りました。
最初、 for
や seq
を試しましたが、 Brace Expansion が便利そうでした。
参考までに、 for
と seq
を使うと次のようになりました。
$ for i in $(seq 65 90); do printf "%x\n" $i; done;
41
42
43
…略…
58
59
5a
seq
だけだと次のようになりました。
$ seq 65 90
65
66
67
…略…
88
89
90
for
や seq
は printf
と組み合わせて使おうとすると、少し面倒になりそうでしたのでやめました。
ASCII 文字の一覧
8 進数
10 進数から 8 進数にして、 ASCII 文字を表示してみます。
$ printf "$(printf '\\%o' {0..127})" | od -t a
0000000 nul soh stx etx eot enq ack bel bs ht nl vt ff cr so si
0000020 dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us
0000040 sp ! " # $ % & ' ( ) * + , - . /
0000060 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
0000100 @ A B C D E F G H I J K L M N O
0000120 P Q R S T U V W X Y Z [ \ ] ^ _
0000140 ` a b c d e f g h i j k l m n o
0000160 p q r s t u v w x y z { | } ~ del
0000200
だぶんできたみたいです。
制御文字はそのままだと確認できないので、 od -t a
にパイプで渡しました。
16 進数
次は、 10 進数から 16 進数にして、 ASCII 文字を表示してみます。
$ printf "$(printf '\\x%x' {0..127})" | od -t a
0000000 nul soh stx etx eot enq ack bel bs ht nl vt ff cr so si
0000020 dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us
0000040 sp ! " # $ % & ' ( ) * + , - . /
0000060 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
0000100 @ A B C D E F G H I J K L M N O
0000120 P Q R S T U V W X Y Z [ \ ] ^ _
0000140 ` a b c d e f g h i j k l m n o
0000160 p q r s t u v w x y z { | } ~ del
0000200
だぶんできたみたいです。
終わり
最初、 for
を使ってみたのですが、この記事を書きながら調べていて、ブレース展開でもできることがわかりました。
調べたらもっとシンプルにできるのかな。
参考
Bash のマニュアルってないのかな、と思っていたのですが、 GNU のがあったみたいでした。
記号とか検索しづらいので、こういうマニュアルはありがたいです。