AWK的输出,主要还是靠 print 和 printf 两个函数,而这两个函数,我们前面已经用过很多次了。
print 和 printf 主要从 C 语言 借鉴而来,而且继承了 C 语言 的输出格式。
本章剩下的内容,我们就来看看 printf 支持哪些输出格式吧。
printf 函数语法
printf fmt, expr-list
参数说明
参数 | 说明 |
---|---|
fmt |
字符串字面量,用于指定输出的格式 |
expr-list |
传递给 fmt 的参数 |
例如下面的 awk printf 函数用法
printf "%d\n", 18
%d\n 是输出格式,用于指定如何输出传递的参数,而 18 则是要输出的参数,用于按照一定的语法替换 fmt 中以 % 开始的格式化符。
%d 这种以 百分号(%) 开始的字符串又称之为 格式化符,由 百分号(%) 和其它预定义的字符构成。
printf 支持的转义字符
AWK的 printf 函数从 C 语言 借鉴而来,那么它所支持的 转义字符 也基本从 C 语言借鉴而来。
因此,如果你熟悉 C 语言的 printf() 函数,那么对于 AWK 的转义字符也会得心应手。
新行(换行符)\n
AWK中的 新行(换行符) \n 表示。
因此,如果你想要 Hello World 中的每一个单词一行
Hello
World
那么你只需要将 Hello World 中的 空格( ' ' ) 换成 \n 即可
[www.ddkk.com]$ awk 'BEGIN { printf "Hello\nWorld\n" }'
运行上面的 awk 命令,输出结果如下
Hello
World
后面那个 \n 是为了保证 终端( shell ) 的提示符在新的一行。
水平分隔符(制表符)\t
如果你想要两个或更多个字符串/字段之间有一定的间隔,一种方法是添加相当数量的 空格,比如我们想要 Hello 和 World 两个单词之间有四个空格,则可以直接使用四个空格分开
Hello World
另一种更简单的方法,就是使用 水平分隔符(制表符)\t 。
Hello\tWorld
一般情况下,一个 \t 的间隙相当于 2 个或 4 个空格,这取决于配置
我们来看一个范例
[www.ddkk.com]$ awk 'BEGIN { printf "编号\t姓名\t部门\t年龄\n";printf "编号 姓名 部门 年龄\n";}'
运行上面的 awk 命令,输出结果如下
编号 姓名 部门 年龄
编号 姓名 部门 年龄
从上面的输出可以看出,在我这台电脑上,一个 \t 等于 4 个空格。
竖直(垂直)分隔符 \v
竖直(垂直)分隔符 \v 看起来有点和 水平分隔符(制表符)\t 类似,但是,前者的功能并不是在竖直方向拉出一定的空间,而是在 新行中空出上一行所占用的空间
简单的来说,就是制作一个 楼梯 效果,比如 "编号\v姓名\v部门\v年龄\n" 的作用,其实是
编号
姓名
部门
年龄
[www.ddkk.com]$ awk 'BEGIN { printf "编号\v姓名\v部门\v年龄\n"}'
运行上面的 awk 命令,输出结果如下
编号
姓名
部门
年龄
退格符 \b
退格符 \b 的作用,就是在之前的字符串基础上,往回退一个 字符。从某些方面说,就是删除一个前面的字符。
比如Hello\bWorld 输出的效果就是 HellWorld,也就是 \b 之前的那个 o 被删除了。
为了更逼真的演示 \b 的作用,请看下面这个范例
[www.ddkk.com]$ awk 'BEGIN { printf "Field 1Field 2Field 3Field 4\n" }'
[www.ddkk.com]$ awk 'BEGIN { printf "Field 1\bField 2\bField 3\bField 4\n" }'
运行上面的 awk 命令,输出结果如下
Field 1Field 2Field 3Field 4
Field Field Field Field 4
从输出结果中可以看出,每一个 \b 都会用于删除前一个字符和 \b 本身
回车符 \r
在很多地方,或许你也经常听到 回车换行,也就是 \r\n,虽然 回车\r 和 换行(\n) 的效果看起来类似,但它们实实在在的有点区别的。
1、 换行符(\n)是在新行继续输出;
2、 **回车符(\r)**则是删除当前行的所有已经输出,然后回到当前行的开始重新输出,从某些方面说,就是从在当前从头开始输出;
3、 回车换行(\r\n)的意思就是回到当前行的开始并且在新行输出,从某些方面说,其实就是换行;
如果你比理解,请反复理解下面这个范例
[www.ddkk.com]$ awk 'BEGIN { printf "Field 1\nField 22\nField 333\nField 4444\n\n" }'
[www.ddkk.com]$ awk 'BEGIN { printf "Field 1\rField 22\rField 333\rField 4444\n\n" }'
[www.ddkk.com]$ awk 'BEGIN { printf "Field 1\r\nField 22\r\nField 333\r\nField 4444\n" }'
运行上面的 awk 命令,输出结果如下
Field 1
Field 22
Field 333
Field 4444
Field 4444
Field 1
Field 22
Field 333
Field 4444
从结果中可以看出,\r\n 和 \n 的作用类似,而 \r 则是实打实的从当前行开始输出
换页符 (\f)
换页符 (\f) 顾名思义,就是 走纸换页,一般在 打印机打印 时才会生效,用于从一个 新页 开始输出。
如果不是在 打印机,那么输出效果和 竖直分割符(\v) 的效果类似
[www.ddkk.com]$ awk 'BEGIN { printf "Sr No\fName\fSub\fMarks\n" }'
[www.ddkk.com]$ awk 'BEGIN { printf "Sr No\vName\vSub\fMarks\n" }'
运行上面的 awk 命令,输出结果如下
Sr No
Name
Sub
Marks
Sr No
Name
Sub
Marks
printf 支持的所有格式化符
AWK的 printf 函数从 C 语言 借鉴而来,那么它所支持的 格式化符 也基本从 C 语言借鉴而来。
因此,如果你熟悉 C 语言的 printf() 函数,那么对于 AWK 的格式化符也会得心应手。
单个字符 %c
如果你想要将一个数字输出为 单个字符,可以使用 %c 格式化符。
需要注意的是
1、 如果传递的是数字,这个数字必须是ASCII所支持的,也就是说小于128;
2、 如果传递的是字符串,那么只有第一个字符会被输出,其它的则直接省略;
[www.ddkk.com]$ awk 'BEGIN { printf "ASCII value 65 = character %c\n", 65 }'
[www.ddkk.com]$ awk 'BEGIN { printf "ASCII value 156 = character %c\n", 156 }'
[www.ddkk.com]$ awk 'BEGIN { printf "ASCII value ddkk = character %c\n", "ddkk" }'
运行上面的 awk 命令,输出结果如下
ASCII value 65 = character A
ASCII value 156 = character ?
ASCII value ddkk = character t
从输出结果中可以看出,如果传递的数字不能转换为 ASCII 字符,则直接输出一个 问号(?)
整数 %d 和 %i
%d 和 %i 格式化符的作用一样,把传递的参数转换为 整数 然后输出。
需要注意的是:
1、 如果传递的是浮点数(小数) ,那么只会输出整数部分,小数部分直接忽略;
2、 如果传递的是非整数,则直接输出0;
3、 如果传递的是字符串整数,则会转换为整数然后输出;
[www.ddkk.com]$ awk 'BEGIN { printf "价格 = %d\n", 80 }'
[www.ddkk.com]$ awk 'BEGIN { printf "价格 = %d\n", 80.66 }'
[www.ddkk.com]$ awk 'BEGIN { printf "价格 = %d\n", "www.ddkk.com" }'
[www.ddkk.com]$ awk 'BEGIN { printf "价格 = %d\n", "80.66" }'
运行上面的 awk 命令,输出结果如下
价格 = 80
价格 = 80
价格 = 0
价格 = 80
科学计数法 %e 和 %E
%e 和 %E 的作用一样,把传递的参数先用 科学计数法 表示然后输出。它们的差别在于 %E 会把科学计数法表示中的所有字母都大写。
需要注意的是:
不管传递的是什么,都会先转换成科学计数法。如果传递的是字符串,首先会转换成 0 然后再转换为科学计数法
[www.ddkk.com]$ awk 'BEGIN { printf "价格 = %e\n", 80 }'
[www.ddkk.com]$ awk 'BEGIN { printf "价格 = %e\n", 80.6699999 }'
[www.ddkk.com]$ awk 'BEGIN { printf "价格 = %e\n", "www.ddkk.com" }'
[www.ddkk.com]$ awk 'BEGIN { printf "价格 = %e\n", "80.66" }'
运行上面的 awk 命令,输出结果如下
价格 = 8.000000e+01
价格 = 8.067000e+01
价格 = 0.000000e+00
价格 = 8.066000e+01
%E 会把科学计数法中的所有字母都大写。
[www.ddkk.com]$ awk 'BEGIN { printf "价格 = %E\n", 80 }'
[www.ddkk.com]$ awk 'BEGIN { printf "价格 = %E\n", 80.6699999 }'
[www.ddkk.com]$ awk 'BEGIN { printf "价格 = %E\n", "www.ddkk.com" }'
[www.ddkk.com]$ awk 'BEGIN { printf "价格 = %E\n", "80.66" }'
运行上面的 awk 命令,输出结果如下
价格 = 8.000000E+01
价格 = 8.067000E+01
价格 = 0.000000E+00
价格 = 8.066000E+01
浮点数格式化符 %f
浮点数格式化符 %f 会把传递的参数先转换为 浮点数(小数) ,然后输出。
需要注意的是:
1、 不管传递的是什么,都会先转换成浮点数如果传递的是字符串,首先会转换成0然后再转换为浮点数;
2、 转换的时候,如果小数位数太多(默认多余6位)则会触发四舍五入;
[www.ddkk.com]$ awk 'BEGIN { printf "价格 = %f\n", 80 }'
[www.ddkk.com]$ awk 'BEGIN { printf "价格 = %f\n", 80.6699999 }'
[www.ddkk.com]$ awk 'BEGIN { printf "价格 = %f\n", "www.ddkk.com" }'
[www.ddkk.com]$ awk 'BEGIN { printf "价格 = %f\n", "80.66" }'
运行上面的 awk 命令,输出结果如下
价格 = 80.000000
价格 = 80.670000
价格 = 0.000000
价格 = 80.660000
格式化符 %g 和 %G
%g 和 %G 的作用是一样的,会根据传递的参数选择 %e 或 %f 格式化符,具体选哪个,取决于转后后的结果谁更短(位数更少)。
而%G 和 %g 的区别,就是前者会把转换后的参数中的所有字母都大写。
1、 当给定的数字去掉首尾的空格后,整数部分总位数小于等于6时,使用的是%f和%F模式,且总共只保留6位数字,还会发生四舍五入;
格式化符 | 说明 | 范例 | 范例结果 |
---|---|---|---|
%g |
浮点数格式输出 | printf "%g",000123.456789213 |
123.457 |
%G |
浮点数格式输出且大写 E | printf "%G",000123.456789213 |
123.456789 |
1、 当给定的数字去掉首尾的空格后,整数部分总位数大于6时,采用的是%e和%E模式,且会去掉首尾的空格,并保留6位有效小数;
格式化符 | 说明 | 范例 | 范例结果 |
---|---|---|---|
%g |
科学计数法输出 | printf "%g",0005678123.456789213 |
5.67812e+06 |
%G |
科学计数法输出且大写 E | printf "%G",0005678123.456789213 |
123.456789 |
八进制 %o
%o 用于输出一个 无符号八进制数字,准确的说是将数据先转换为无符号八进制数据然后输出
[www.ddkk.com]$ awk 'BEGIN { printf "Octal representation of decimal number 10 = %o\n", 10}'
运行以上 awk 命令,输出结果如下
Octal representation of decimal number 10 = 12
%u
格式化符 %u 用于输出一个 无符号十进制数字,准确的说是将数据先转换为无符号十进制数据然后输出
[www.ddkk.com]$ awk 'BEGIN { printf "无符号 10 = %u\n", 10 }'
运行以上 awk 命令,输出结果如下
无符号 10 = 10
而对于小于 0 的数据,则会先转换为无符号十进制数字再输出,转换方式为先抛弃小数,然后求补码。s
[www.ddkk.com]$ awk 'BEGIN { printf "无符号 -11.332 = %u\n", -11.332 }'
运行以上 awk 命令,输出结果如下
无符号 -11.332 = 18446744073709551605
%s
格式化符 %s 用于输出一个字符串。准确的说是将数据先转换为字符串,然后输出
[www.ddkk.com]$ awk 'BEGIN { printf "年龄 = %s\n", 28.1119 }'
运行以上 awk 命令,输出结果如下
年龄 = 28.1119
当然了,%s 还可以原样输出传递的字符串,例如
[www.ddkk.com]$ awk 'BEGIN { printf "网站 = %s\n", "/"}'
运行以上 awk 命令,输出结果如下
网站 = /
%x and %X
格式化符 %x 和 %X 可以用来将一个 大于 0 的十进制 格式化为 十六进制
而%X 和 %x 的区别,就是 %X 格式化生成的十六进制是大写字母,而 %x 则是小写字母
[www.ddkk.com]$ awk 'BEGIN { printf "15 转换为十六进制为: = %x\n", 15}'
运行以上 awk 命令,输出结果如下
15 转换为十六进制为: = f
如果我们把 %x 改成 %X 则会输出大写的十六进制
[www.ddkk.com]$ awk 'BEGIN { printf "15 转换为十六进制为: = %X\n", 15}'
运行以上 awk 命令,输出结果如下
15 转换为十六进制为: = F
输出百分号 %%
已经学习了这么多的格式化符,我们知道,任何格式化符都是以 百分号(%) 开始的
那么,如果我们要输出 % 又要怎么做呢?
答案就是: 和 C 语言 一样,使用 两个百分号(%%) 来输出一个 %
[www.ddkk.com]$ awk 'BEGIN { printf "百分比 = %d%%\n", 80.66 }'
运行上面的 awk 命令,输出结果如下
百分比 = 80%
百分号(%) 的其它格式化符号
百分号(%) 还有一些其它非常有用的格式化组合,下面我们就来讲讲几个比较常见的
指定占用宽度
AWK使用 printf 输出时,默认是参数多长就输出多长,不会浪分一丁点空间。
但如果我们想要位某个参数指定固定的长度,则可以在 百分号(%) 后面,格式化字符之前添加指定的 长度。
例如,对于 %d 如果我们要指定占用宽度为 10 ,则可以使用格式化符 %10d。
默认情况下,当输出是 右对齐的,且左边默认填充 空格(' ')。
[www.ddkk.com]$ awk 'BEGIN {
num1 = 10; num2 = 20; printf "Num1 = %10d\nNum2 = %10d\n", num1, num2
}'
运行上面的 awk 命令,输出结果如下
Num1 = 10
Num2 = 20
左对齐
在我们指定了宽度的前提下,AWK 有条默认的规则: 当输出的数字不足以填满宽度时,默认是右对齐的。例如下面的范例
[www.ddkk.com]$ awk 'BEGIN { num1 = 10;num2 = 12356; printf "Num1 = %7d\nNum2 = %7d\n", num1,num2 }' | cat -vte
输出结果如下
Num1 = 10$
Num2 = 12356$
上面的范例,有两个地方值得注意:
1、 输出默认时左对齐的,因此Num1=和Num2=垂直对齐且左对齐;
2、 当指定了宽度,默认时右对齐的10和123456就时右对齐;
如果我们想要输出的数字不足以填满宽度时仍然左对齐,则需要在百分号后类型之前面添加 负号(-)。
对于上面的范例,就是将 %7d 改成 %-7d
[www.ddkk.com]$ awk 'BEGIN { num1 = 10;num2 = 12356; printf "Num1 = %-7d\nNum2 = %-7d\n", num1,num2 }' | cat -vte
运行上面的范例,输出结果如下
Num1 = 10 $
Num2 = 12356 $
前缀的 0
不知道你有没有留意上一条的数组结果。哈哈,去翻翻~~~~
在我们指定了宽度的前提下,AWK 还有另一条默认的规则: 当输出的数字不足以填满宽度时,默认右对齐的,且使用空格补足剩余部分。
例如下面的范例
[www.ddkk.com]$ awk 'BEGIN { num1 = 10;num2 = 12356; printf "Num1 = %7d\nNum2 = %7d\n", num1,num2 }' | cat -vte
输出结果如下
Num1 = 10$
Num2 = 12356$
这时候,如果要将默认的 空格填充 改成 0 ,比如 0 ,则需要在 百分号(%) 后面,宽度数字之前 添加 0 ,例如 %7d 改成 %07d
注意: 只能是 0 ,如果是其它字符,默认是没有任何效果的。
[www.ddkk.com]$ awk 'BEGIN {
num1 = -10; num2 = 20; printf "Num1 = %07d\nNum2 = %07d\n", num1, num2
}'
运行上面的 awk 命令,输出结果如下
Num1 = -000010
Num2 = 0000020
数字前缀的正负号
AWK支持输出时在数字前面添加 正负号(+-),也就是说,把 10.00 改成 +10.00,把 -10.00 改成 -10.00
哈,其实负数没啥好添加前缀的,因为人家本来就有一个 负号
要在数字前面添加正负号,只需要在 百分号(%) 后类型之前添加一个 **正号(+)**即可,比如 %d 改成 %+d,比如 %f 改成 %+f
[www.ddkk.com]$ awk 'BEGIN {
num1 = -10; num2 = 20; printf "Num1 = %+d\nNum2 = %+d\n", num1, num2
}'
输出结果为
Num1 = -10
Num2 = +20
比如
[www.ddkk.com]$ awk 'BEGIN {
num1 = -10.234; num2 = 20.456; printf "Num1 = %+f\nNum2 = %+f\n", num1, num2
}'
输出结果为
Num1 = -10.234000
Num2 = +20.456000
数字格式化
AWK的输出还支持对数字进行格式化,比如八进制、十六进制、小数点、千分位等。具体的规则如下
1、 如果给定的值不为0,则支持八进制输出和十六进制输出;
格式化符 | 说明 | 范例 | 范例结果 |
---|---|---|---|
%o |
八进制格式 | printf("%o",10) | 12 |
%#o |
八进制且附加前缀 0 |
printf("%#o",10) | 012 |
%x |
十六进制格式 | printf("%x",10) | a |
%X | 大写十六进制格式 | printf("%X",10) | A |
%#x |
十六进制格式附加前缀 0x |
printf("%#x",10) | 0xa |
%#X|大写十六进制格式附加前缀 0X |
printf("%#X",10) | 0XA |
如果给定的值为 0 则会直接输出 0 而无视各种格式符
1、 对于任意数字,都是支持以下科学计数法输出;
格式化符 | 说明 | 范例 | 范例结果 |
---|---|---|---|
%e |
科学计数法输出 | printf "%e",123.456789213 |
1.234568e+02 |
%E |
科学计数法输出且大写 E | printf "%E",123.456789213 |
1.234568E+02 |
%e 和 %E 并会移除前置的 0,比如下面这个范例
awk 'BEGIN { printf "%e\n", 000001231.456789213}'
输出结果为
1.231457e+03
1、 对于任意数字,都支持以下浮点数格式化符;
格式化符 | 说明 | 范例 | 范例结果 |
---|---|---|---|
%e |
科学计数法输出 | printf "%f",123.456789213 |
123.456789 |
%E |
科学计数法输出且大写 E | printf "%F",123.456789213 |
123.456789 |
注意: Mac OS 自带的 awk 不支持 %F
%f 和 %F 并会移除前置的 0,比如下面这个范例
awk 'BEGIN { printf "%f\n", 000001231.456789213}'
输出结果为
1231.456789
1、 对于任意数字,还支持以下浮点数格式化符;
%g 和 %G 是 %e、%E、%f、%F 的升级版。
1、 当给定的数字去掉首尾的空格后,整数部分总位数小于等于6时,使用的是%f和%F模式,且总共只保留6位数字,还会发生四舍五入;
格式化符 | 说明 | 范例 | 范例结果 |
---|---|---|---|
%g |
浮点数格式输出 | printf "%g",000123.456789213 |
123.457 |
%G |
浮点数格式输出且大写 E | printf "%G",000123.456789213 |
123.456789 |
格式化符 | 说明 | 范例 | 范例结果 |
---|---|---|---|
%g |
科学计数法输出 | printf "%g",0005678123.456789213 |
5.67812e+06 |
%G |
科学计数法输出且大写 E | printf "%G",0005678123.456789213 |
123.456789 |