shell之printf
本文记录的是shell之printf格式化输出.
首先看看其 man page 内容:
1 | NAME |
从上述 man page 内容可以看出:
printf
通过format
字符串格式化输出其后的arguments
;format
字符串包含三种类型对象: 普通字符串,该对象输出时会直接拷贝到标准输出STDOUT
;字符转义序列,通过字符转义之后输出到标准输出;格式说明符,每一个格式说明符对应输出相应的argument
;- 如果对应的格式指示符是
%c
/%b
/%s
时,相对应的参数都视为字符串,否则它们会被解释为C语言的数字常量: 在其开头可使用正负号标识;如果字符串开头是单引号'
或者双引号"
,那么打印输出的值是紧跟着单引号或者双引号后的那个字符的ASCII
值
关于%c
/%b
/%s
,其 man
page的说明如下:
1 | c: The first character of argument is printed. |
从上面的文档可以看出:
- 若使用
%c
指示符,则指打印输出参数中的第一个字符,会忽略其它字符; - 若使用
%s
指示符,则打印整个字符串参数,或者打印控制精度控制的字符个数,如果精度值是0或者没有控制精度值,则打印所有的字符值。 - 使用
%s
时,在格式指示符中的转义字符能够被解析,而参数列表中的转义字符则不会被解析,但是若使用%b
指示符,printf会解析格式指示符和参数列表中的转义字符,其后的参数列表需要用双引号
对于以上说明,举以下几个例子:
1 | $ printf "hello world\n" |
上例中输出了普通字符串+转义字符,可以看出,printf不同于echo会默认输出\n
,使用printf输出新的一行必须在末尾加上\n
1 | $ printf "hello %c, %s\n" "China" "World" |
上例中使用了%c
格式指示符,只打印出来对应参数的第一个字符,忽略了该参数的其他字符
1 | $ printf "hello\tworld, welcome to%s\n" "\tChina" |
上例中第一种情况,只解析了format
字符串中的转义字符,而未解析使用%s
格式指示符控制的参数中的转义字符,而使用%b
控制时,能够解析参数中的转义字符.
1 | $ printf "hello %b see u\n" hjkl\taa |
上例是使用%b
指示符解析参数中的转义字符时,参数未用双引号包含和使用双引号包含的情况对比。
1 | $ printf "hello u are %s\n" "'a" |
上例是
参数字符串开头是单引号'
或者双引号"
时,那么打印输出的值是紧跟着单引号或者双引号后的那个字符的ASCII
值
的实例
关于格式方面的几个转义字符:
1 | \a 警告声音输出. |
下面说说上述转义字符中的\c
与\f
。
1 | $ printf "ab%sc%bdef%s" "AAA\n" "JQK\cioio" "China" |
\c
需要与%b
配合使用,若使用的是%s
,则会原样输出,如上例的AAA\n
参数;注意上例中的%b
和参数JQK\cioio
,遇到\c
后,忽略了该参数后的字符ioio
,也忽略了%b
指示符后所有格式说明,包括普通字符def
以及格式占位符%s
。
1 | $ printf "hello a\fbbbbbkkdkkdk\flodldidkcmmjjd\n" |
上述是\f
转义字符的示例,我也不知道该做何解释,领悟吧.
每一个格式占位符都是以%
引出,接下来的格式说明符可以按以下顺序包括:
- 0个或者多个标志位,这里暂且称为位置标识,稍后解释。
- Field Width, 字段宽度。
- 精度控制
- 参数格式类型
其中,上述位置标识包括:
#
: 该字符指示参数应该进行格式转换。对于%c
/%d
/%s
格式类型,该选项不产生影响;对于%o
强制其精度值增加,使其输出字符串的第一个字符为0
;对于%x
/%X
,会有0x
(0X
)加在参数开头; 对于%e
/%E
/%f
/%g
/%G
,在输出结果中总会包含有小数点,即使小数点后没有任何数字.-
: 该字符指定对应的参数字段使用左对齐方式.+
: 该字符指定,在输出有符号形式的数字时,在数字前总应该有相应符号.: 空格符,该符号指示在输出有符号形式的数字时,如果该数字是正数,则在该正数前应该有一空格,如果是负数,则在空格位置是
-
;如果使用了+
位置标识,则该位置标识不起作用.0
: 该指示符表示,应该使用0
填充代替空格填充,如果使用-
位置标识,则该位置标识不起作用.
位置标识的示例如下:
1 | $ printf "hello %#s\n" "world, hey" |
上例中看出#
对%s
格式类型无影响
1 | $ printf "this is octonary number: %o\n" "123" |
上例中看出,对于八进制和十六进制数字,使用#
后会在参数前添加0
或者0x
1 | $ printf "Field width: |%10s|\t|%-10s|\n" "hello" "world" |
上例中看出,使用-
指示符之后,参数实行左对齐
1 | $ printf "signed number: %+d\n" 3456 |
上例中看出,使用+
指示符之后,输出有符号数字时会在数字前加上+
/-
1 | $ printf "padding number:% d\n" 3456 |
上例中看出使用空格指示符之后,输出正数时,会在正数前添加一个空格,输出负数时,会使用-
填补空格处,如果同时使用了+
指示符,则空格指示符不起作用
1 | $ printf "padding number:|%5d|\n" 23 |
上例中看出使用0
指示符之后,输出的数字会在左边补0,如果同时使用了左对齐-
指示符,那么0
指示符不起作用
接下来说说字段宽度控制。
1 | $ printf "padding number:|%5d|\n" -2345678 |
如上例所示,使输出的整数5个字符宽度,如果数字宽度大于5,那么使用实际宽度(不进行截断), 如果数字宽度小于5,那个左边使用空格占位补齐,如果使用的左对齐方式,那么右边使用空格占位补齐
接下来说说输出的精度控制。精度控制使用一个小数点加上紧接着的数字(精度值)表示.对于%e
和%f
格式类型,精度控制指定的是小数点后可保留的小数点位数;对于字符串参数则表示可输出的最大字符个数;如果小数点后的精度值没有,那么则是将精度值视为0
1 | $ printf "padding number:|%.2f|\n" -23.9876543 |
上例中第一种情形,保留2位小数,第二种情形,没有精度控制值,只有.
,表示不保留小数部分,第三和第四种情形是针对字符的输出控制。
最后说明,参数格式类型使用单一字符标识(one of
diouxXfFeEgGaAcsb
).从之前的例子中已经看到部分类型的使用。
对于字段宽度控制和精度控制中,可能会使用*
代替数字,这种情况下,由参数控制字段的宽度和输出精度。
对于参数格式类型控制字符diouxXfFeEgGaAcsb
说明如下:
diouXx
:
指示参数会以带有符号的十进制数输出(d
或者i
),
无符号八进制(o
),
无符号十进制(u
),以及无符号十六进制(x
或X
)
fF
:
指示参数会以[-]ddd.ddd
的格式输出,其中小数点后的d
个数等同于参数的精度控制,如果没有精度控制值,则使用默认值6;如果精度值是0,那么不会输出小数点及任何小数部分.
The values infinity and NaN are printed as inf
and
nan
, respectively.
eE
:
指示参数以[-d.ddd+-dd]的格式输出,在小数点前面会有一位数字,小数点后的数字位数由精度值控制,如果没有精度控制值,则使用默认值6;The
values infinity and NaN are printed as inf
and
nan
, respectively.
gG
: The argument is printed in style f (F) or in style e
(E) whichever gives full precision in minimum space.
aA
: The argument is printed in style
[-h.hhh+-pd] where there is one digit before the
hexadecimal point and the number after is equal to the precision
specification for the
argument; when the precision is missing, enough digits are
produced to convey the argument's exact double-precision floating-point
representation. The values infinity and NaN are printed as
inf
and nan
, respectively.
%
: Print a %
; no argument is used.
In no case does a non-existent or small field width cause truncation
of a field; padding takes place only if the specified
field width exceeds the actual width.
下面看几个例子来理解。
1 | $ printf "float number: %f\n" 1342.78654329 |
上面的例子中第一种情形展示的精度控制默认值(小数点后6位);第二种情形表示保留小数点后4位;第三种情形表示没有精度控制值时忽略小数点及小数。
1 | $ printf "float number: |%.e|\n" -1342.78654329 |
上面是eE
的例子。
1 | $ printf "significant digit control: %.4G\n" 123456.3456256789 |
最后再次说明一种格式:
%N.nf
:
其中N表示浮点数所占有的总的宽度,包括小数点,n表示小数点的个数,如下:
1 | $ printf "|%6.2f|\n" 567.98765442 |