我正在尝试使用 awk,我认为编写一个小程序将每个 ASCII 字符与其十六进制代码映射是一个很酷的主意。这就是我到目前为止所做的:
该字符串是:
abshdfitiggwigiwjirjgiejrigjr
我保持简单,不包括回车或制表符等
我将其转储到一个用逗号分隔的文件中,以便我可以使用 awk 的 -F 标志将它们识别为字段:
a,b,s,h,d,f,i,t,i,g,g,w,i,g,i,w,j,i,r,j,g,i,e,j,r,i,g,j,r,
我对同一文件的十六进制转储做了同样的事情:
61,62,73,68,64,66,69,74,69,67,67,77,69,67,69,77,6a,69,72,6a,67,69,65,6a,72,69,67,6a,72,0a,
我现在想,因为它们都有相同的 NF,所以会更容易,所以我尝试了以下 awk 命令:
awk -F ',' '{for(i=1;i<NF;i++){sum[$i]=$i}} END {for(char in sum) { print char, sum[char]} } ' line.txt linebits.txt
其中 line.txt 和 linebits.txt 对应于正确的文件
输出如下:
62 62
h h
72 72
i i
0a 0a
64 64
73 73
j j
w w
65 65
74 74
66 66
67 67
77 77
68 68
a a
69 69
b b
6a 6a
d d
e e
r r
f f
s s
61 61
g g
t t
这当然是有道理的,因为 sum[$i]=$i 只是在做 sum[g]=g ,并且我打印的两者是相同的
我知道为什么它显示这个输出,但我不知道如何修复它。
是否可以指定我想要哪个文件?是否可以获取标准输入的索引?我知道这听起来很疯狂哈哈
我想要的输出是:
char - hex code
char - hex code
.....
答案1
听起来您的目标是学习(关于)awk,而不是简单地获取 ASCII 表,而其他答案很容易获得该表。
为此,您不需要任何输入文件;您可以直接显示所有可打印字符
awk 'BEGIN{ for(i=32;i<127;i++) printf("%02x %c\n",i,i) }'
(这会生成一长列,就像您的尝试一样;如果您想要多列,则将其作为练习。)
OTOH,如果您想组合两行中的字段对 - 可以是任何值,而不仅仅是字符及其十六进制:
awk [-Fasneeded] 'NR==1 { for(i=1;i<=NF;i++) save[i]=$i; next }
{ for(i=1;i<=NF;i++) print save[i],$i }' file ...
# linebreak for ease of reading, may be omitted in use
无论这两行来自两个文件(如您的情况)还是来自一个文件,这都有效。如果您有两行以上,则会将第 1 行到每个后续行的字段配对,这种模式对于 CSV 类型文件通常有意义,这些文件在第 1 行上有一个标题,其中包含每列的名称,后跟可变数量的行每列中都有数据。
这也保留了包括任何欺骗在内的顺序。为了消除欺骗但保持秩序:
awk [-Fasneeded] 'NR==1 { for(i=1;i<=NF;i++) save[i]=$i; next }
{ for(i=1;i<=NF;i++) if(!dupe[$i]++) print save[i],$i ;delete dupe }' file ...
# the delete dupe can be omitted in the two-line case
如果你真的想要由此创建的随机顺序for in
也是可能的,但这对我来说没有意义。一些有用诸如数字顺序或字母顺序(消除重复)之类的顺序可能是有意义的。
答案2
您已经获得了更简单的方法,但由于这里的目标似乎是学习 awk,因此我将如何使用您描述的方法来做到这一点。首先,我不会使用,
分离,使用线条来完成类似的事情会更容易。然后我们可以使用NR
和FNR
特殊变量来连接这两个文件。NR
保存当前输入行号,而FNR
输入行号当前正在读取的文件的。因此,如果我们给出awk
两个文件,每个文件有 2 行,那么NR
将从 到1
,4
但在读取第二个文件的第一行时,FNR
将从 到 然后回到1
,2
然后。1
2
把它们放在一起,我们可以做到:
## get the characters, one per line
printf '%s\n' {a..z} > chars
## get the 2byte codes as you had in the question. I am sure
## there is a simpler way, but this is the best I could come up with
hexdump -x chars | tr -s ' ' '\n' | sed -n 's/^0a//p' > codes
有了这些文件,我们可以执行以下操作:
## Use awk to print them in pairs
$ awk '{ if(NR==FNR){chars[FNR]=$1} else{ print chars[FNR],$1}}' chars codes
a 61
b 62
c 63
d 64
e 65
f 66
g 67
h 68
i 69
j 6a
k 6b
l 6c
m 6d
n 6e
o 6f
p 70
q 71
r 72
s 73
t 74
u 75
v 76
w 77
x 78
y 79
z 7a
当然,这也可以使用 来完成paste
,但没关系:
$ paste chars codes
a 61
b 62
c 63
d 64
e 65
f 66
g 67
h 68
i 69
j 6a
k 6b
l 6c
m 6d
n 6e
o 6f
p 70
q 71
r 72
s 73
t 74
u 75
v 76
w 77
x 78
y 79
z 7a
答案3
如果您使用 GNU awk
,那么您可以包含扩展库ordchr
:
echo abshdfitiggwigiwjirjgiejrigjr |
awk -lordchr -F '' '{for(i=1;i<=NF;i++)printf "%c %x\n", $i, ord($i)}'
a 61
b 62
s 73
h 68
...
ord()
-函数,将 char 转换为十进制
printf "%x", ord($i)
-将十进制转换为十六进制
此外:chr()
-将小数转换为字符
答案4
为什么不使用现有的程序而不是编写自己的程序呢?我建议ascii
来自埃里克·S·雷蒙德。
要使用上述命令输出 ASCII 字符的十六进制值,请执行以下命令:ascii -x
.
输出示例:
00 NUL 10 DLE 20 30 0 40 @ 50 P 60 ` 70 p
01 SOH 11 DC1 21 ! 31 1 41 A 51 Q 61 a 71 q
02 STX 12 DC2 22 " 32 2 42 B 52 R 62 b 72 r
03 ETX 13 DC3 23 # 33 3 43 C 53 S 63 c 73 s
04 EOT 14 DC4 24 $ 34 4 44 D 54 T 64 d 74 t
05 ENQ 15 NAK 25 % 35 5 45 E 55 U 65 e 75 u
06 ACK 16 SYN 26 & 36 6 46 F 56 V 66 f 76 v
07 BEL 17 ETB 27 ' 37 7 47 G 57 W 67 g 77 w
08 BS 18 CAN 28 ( 38 8 48 H 58 X 68 h 78 x
09 HT 19 EM 29 ) 39 9 49 I 59 Y 69 i 79 y
0A LF 1A SUB 2A * 3A : 4A J 5A Z 6A j 7A z
0B VT 1B ESC 2B + 3B ; 4B K 5B [ 6B k 7B {
0C FF 1C FS 2C , 3C < 4C L 5C \ 6C l 7C |
0D CR 1D GS 2D - 3D = 4D M 5D ] 6D m 7D }
0E SO 1E RS 2E . 3E > 4E N 5E ^ 6E n 7E ~
0F SI 1F US 2F / 3F ? 4F O 5F _ 6F o 7F DEL