awk

Pretty Printing Using printf

漂亮的输出使用printf

语法:

printf "print format", variable1, variable2, etc.

打印格式里的特殊字符

下面是一些在一个printf里面被使用的特殊字符。

Special Character Description
\n New Line
\t Tab
\v Vertical Tab
\b Backspace
\r Carriage Return
\f Form Feed

下面打印Line1和Line2 使用换行符分隔行:

$ awk 'BEGIN{printf "Line 1\nLine 2\n"}'
Line 1
Line 2

下面输出不同字段用tab分隔,Field 1后面两个tabs

$ awk 'BEGIN {printf "Field 1\t\tField 2\tField 3\tField 4\n"}'
Field 1        Field 2    Field 3    Field 4

下面打印垂直tabs在每个字段后面:

$ awk 'BEGIN {printf "Field 1\vField 2\vField 3\vField 4\n"}'
Field 1
       Field 2
              Field 3
                     Field 4

下面打印每个字段后面的退格除了Field4. 擦除一至三字段里最后的数字。比如Field 1显示为Field,因为最后特殊字符是使用backspace擦除。不管如何最后一个字符Field 4输出自己,因为我们没有一个\b在Field后面。

$ awk 'BEGIN {printf "Field 1\bField 2\bField 3\bField 4\n"}'
Field Field Field Field 4

在下面的例子里,打印每个字段后,我们做了一个Carriage Return,输出下一个值在当前输出值之上。这意味着,最终输出你看到的仅Field 4,因为它最后一个被打印在所有先前字段之上。

$ awk 'BEGIN {printf "Field 1\rField 2\rField 3\rField 4\n"}'
Field 4
$ awk 'BEGIN {printf "Field 1\fField 2\fField 3\fField 4\n"}'
Field 1
       Field 2
              Field 3
                     Field 4

使用OFS,ORS值打印

当你打印多个值,使用逗号分隔,使用print命令(非printf),它使用OFS和RS内置变量值来决定如何打印字段。

下面的例子显示了如何简单打印,通过OFS和ORS值打印"print $2,$3" 的效果。

$ cat print.awk
BEGIN {
    FS=",";
    OFS=":";
    ORS="\n--\n";
    }
    {
    print $2,$3
    }

$ awk -f print.awk items.txt
HD Camcorder:Video
--
Refrigerator:Appliance
--
MP3 Player:Audio
--
Tennis Racket:Sports
--
Laser Printer:Office
--

printf不使用OFS,ORS值

printf不使用OFS,ORS值,它只使用指定格式在prinf命令里,如下面例子显示。

$ cat printf1.awk
BEGIN {
    FS=",";
    OFS=":";
    ORS="\n--\n";
    }
    {
    printf "%s^^%s\n\n",$2,$3
    }

$ awk -f printf1.awk items.txt
HD Camcorder^^Video

Refrigerator^^Appliance

MP3 Player^^Audio

Tennis Racket^^Sports

Laser Printer^^Office

printf格式说明符(格式化输出)

Format Specifier Description
s String
c Single Character
d Decimal
e Exponential Floating point
f Fix Floating point
g Uses either e or f depending on which is smaller for the given input
o Octal
x Hexadecimal
% Prints the percentage symbol

下面的例子显示格式化说明符的基本用法:

$ cat printf-format.awk
BEGIN {
 printf "s--> %s\n", "String"
 printf "c--> %c\n", "String"
 printf "s--> %s\n", 101.23
 printf "d--> %d\n", 101.23
 printf "e--> %e\n", 101.23
 printf "f--> %f\n", 101.23
 printf "g--> %g\n", 101.23
 printf "o--> %o\n", 0x8
 printf "x--> %x\n", 16
 printf "percentage--> %%\n", 17
}

$ awk -f printf-format.awk
s--> String
c--> S
s--> 101.23
d--> 101
e--> 1.012300e+02
f--> 101.230000
g--> 101.23
o--> 10
x--> 10
percentage--> %

打印固定列宽(基本)

要创建一个固定列宽报告,你必须指定一个数字紧接在%之后在格式说明符里。此数字表示要被打印的字符的最小数目。当输入字符小于指定数量时,空格被添加到左边使它固定宽度。

下面例子显示了基本的使用,printf语句和%后立即被指定的数字

$ cat printf-width.awk
BEGIN    {
    FS=",";
    printf "%3s\t%10s\t%10s\t%5s\t%3s\n","Num","Description","Type","Price","Qty"
    printf "--------------------------------------------------------------------------\n"
    }
    {
    printf "%3d\t%10s\t%10s\t%g\t%d\n", $1,$2,$3,$4,$5
    }

$ awk -f printf-width.awk items.txt
Num    Description          Type    Price    Qty
--------------------------------------------------------------------------
101    HD Camcorder         Video    210    10
102    Refrigerator     Appliance    850    2
103    MP3 Player         Audio    270    15
104    Tennis Racket        Sports    190    20
105    Laser Printer        Office    475    5

请注意,输出有点不齐,尽管我们指定了精确的宽度。那是因为我们指定的宽度实际上是最小宽度,而不是绝对的大小;如果输入字符串具有更多的字符,整个字符串将被打印,因此你应该注意你想要多少个字符被打印。

如果你想打印一个固定的列宽即使输入的字符串的长度超过规定的数量,你应该使用substr函数(或)格式标识符码前加上一个小数(后面会解释)。

在前面的例子中,第二个字段宽度超过指定的10个字符的宽度,因此结果不是打算中的。空格被添加到左边打印good使用一个6字符串。

$ awk 'BEGIN {printf "%6s\n","good"}'
  good

整个字符串被打印在这里,即使你指定的是6字符宽度:

$ awk 'BEGIN {printf "%6s\n","good boy!"}'
good boy!

打印固定宽度(左对齐)

当输入字符串小于指定字符数时,并且你想它左对齐(增加空格到右边),使用负符号(-),接着%号并在数据之前。

"%6s" 是右对齐,显示如下:

$ awk 'BEGIN {printf "|%6s|\n","Good"}'
|  Good|

"%-6s" 是左对齐,显示如下:

$ awk 'BEGIN {printf "|%-6s|\n","Good"}'
|Good  |

在价格数前面添加一个美元符号,只需要增加一个$符号在printf里的标识符之前,显示如下:

$ cat printf-width2.awk
BEGIN    {
    FS=",";
    printf "%-3s\t%-10s\t%-10s\t%-5s\t%-3s\n", "Num","Description","Type","Price","Qty"
    printf "----------------------------------------------------------------------\n"
    }
    {
    printf "%-3d\t%-10s\t%-10s\t$%-.2f\t%-d\n", $1,$2,$3,$4,$5
    }

$ awk -f printf-width2.awk items.txt
Num    Description    Type          Price    Qty
----------------------------------------------------------------------
101    HD Camcorder    Video         $210.00    10
102    Refrigerator    Appliance     $850.00    2
103    MP3 Player    Audio         $270.00    15
104    Tennis Racket    Sports        $190.00    20
105    Laser Printer    Office        $475.00    5

默认值是用空格添加到左右对齐。

$ awk 'BEGIN{printf "|%5s|\n", "100"}'
|  100|

右对齐使用0在数据之前(代替空格),增加一个零(0)在数字之前,比如使用"%05s”代替 "%5s”作为格式标识符。

$ awk 'BEGIN{printf "|%05s|\n", "100"}'
|00100|

下面示例使用前导0格式标识符为Qty字段。

$ cat printf-width3.awk
BEGIN {
    FS=",";
    printf "%-3s\t%-10s\t%-10s\t%-5s\t%-3s\n","Num","Description","Type","Price","Qty"
    printf "---------------------------------------------------------------------\n"
    }
    {
    printf "%-3d\t%-10s\t%-10s\t$%-.2f\t%03d\n",$1,$2,$3,$4,$5
    }

$ awk -f printf-width3.awk items.txt
Num    Description    Type          Price    Qty
---------------------------------------------------------------------
101    HD Camcorder    Video         $210.00    010
102    Refrigerator    Appliance     $850.00    002
103    MP3 Player    Audio         $270.00    015
104    Tennis Racket    Sports        $190.00    020
105    Laser Printer    Office        $475.00    005

正如我们已经向你演示的,当输入字符串包含多个字符超过在格式标识符里指定的。它将打印整个,如下所示。

$ awk 'BEGIN {printf "%6s\n", "Good Boy!"}'
Good Boy!

要打印最多仅6个字符,增加一个小数点在数字前面,比如用"%.6s”代替"%6s”,这将只打印6个字符从输入字符,即使输入的字符比它长,显示如下:

$ awk 'BEGIN {printf "%.6s\n", "Good Boy!"}'
Good B

在awk所有版本上上面例子是不工作的。在GAWK 3.1.5它是工作的。但是在GAWK 3.1.7,它不工作。

所以,要打印固定字符的可靠方法可能是使用substr函数,如下所示。

$ awk 'BEGIN {printf "%6s\n", substr("Good Boy!",1,6)}'
Good B

Dot . Precision

在格式标识符里一个点号在数字之前表示精度。

下面的例子演示一个.号在格式标识符数字之前是如何工作的。这个例子显示数字"101.23”当使用.1和.4 时,输出差别(使用d,e,f,和g格式说明)。

$ cat dot.awk
BEGIN {
    print "----Using .1----"
    printf ".1d-->%.1d\n",101.23
    printf ".1e-->%.1e\n",101.23
    printf ".1f-->%.1f\n",101.23
    printf ".1g-->%.1g\n",101.23
    print "----Using .4----"
    printf ".4d-->%.4d\n",101.23
    printf ".4e-->%.4e\n",101.23
    printf ".4f-->%.4f\n",101.23
    printf ".4g-->%.4g\n",101.23
    }

$ awk -f dot.awk
----Using .1----
.1d-->101
.1e-->1.0e+02
.1f-->101.2
.1g-->1e+02
----Using .4----
.4d-->0101
.4e-->1.0123e+02
.4f-->101.2300
.4g-->101.2

在awk脚本里,你可以将一个打印语句输出重定到一个指定的文件里。在下面的例子里,第一个打印语句有一个"> report.txt”,它创建一个report.txt文件并且发送打印语句的输出到这个文件里。所有后续的打印语句有一个">> report.txt”,这将输出追加到现在的report.txt文件里。

$ cat printf-width4.awk
BEGIN {
    FS=","
    printf "%-3s\t%-10s\t%-10s\t%-5s\t%-3s\n","Num","Description","Type","Price","Qty" > "report.txt"
    printf    "-----------------------------------------------------\n" >> "report.txt"
    }
    {
    if ($5 > 10)
        printf "%-3d\t%-10s\t%-10s\t$%-.2f\t%03d\n",$1,$2,$3,$4,$5 >> "report.txt"
    }

$ awk -f printf-width4.awk items.txt

$ cat report.txt
Num    Description    Type          Price    Qty
-----------------------------------------------------
103    MP3 Player    Audio         $270.00    015
104    Tennis Racket    Sports        $190.00    020

另一个方法是不指定 "> report.txt" 或 ">> report.txt" 在print语句里,替代的方法是,当执行awk脚本时,重定向输出到report.txt文件,如下所示。

$ cat printf-width5.awk
BEGIN {
    FS=","
    printf "%-3s\t%-10s\t%-10s\t%-5s\t%-3s\n","Num","Description","Type","Price","Qty"
    printf    "-----------------------------------------------------\n"
    }
    {
    if ($5 > 10)
        printf "%-3d\t%-10s\t%-10s\t$%-.2f\t%03d\n",$1,$2,$3,$4,$5
    }

$ awk -f printf-width5.awk items.txt > report.txt

$ cat report.txt
Num    Description    Type          Price    Qty
-----------------------------------------------------
103    MP3 Player    Audio         $270.00    015
104    Tennis Racket    Sports        $190.00    020