• (10)print、printf、sprintf和重定向


    输出操作

    awk可以通过print、printf将数据输出到标准输出或重定向到文件。

    print

    print elem1,elem2,elem3...
    print(elem1,elem2,elem3...)

    逗号分隔要打印的字段列表,各字段都会自动转换成字符串格式,然后通过预定义变量OFS(output field separator)的值(其默认值为空格)连接各字段进行输出。

    [root@docker-01 ~]# awk 'BEGIN{print "hello","world"}'
    hello world
    [root@docker-01 ~]#  awk 'BEGIN{OFS="-";print "hello","world"}'
    hello-world

    print要输出的数据称为输出记录,在print输出时会自动在尾部加上输出记录分隔符,输出记录分隔符的预定义变量为ORS,其默认值为

    [root@docker-01 ~]# awk 'BEGIN{OFS="-";ORS="_
    ";print "hello","world"}'
    hello-world_

    括号可省略,但如果要打印的元素中包含了特殊符号>,则必须使用括号包围(如print("a" > "A")),因为它是输出重定向符号。

    如果省略参数,即print;等价于print $0;

    print输出数值

    print在输出数据时,总是会先转换成字符串再输出。

    对于数值而言,可以自定义转换成字符串的格式,例如使用sprintf()进行格式化。

    print在自动转换数值(专指小数)为字符串的时候,采用预定义变量OFMT(Output format)定义的格式按照sprintf()相同的方式进行格式化。OFMT默认值为%.6g,表示有效位(整数部分加小数部分)最多为6。

    [root@docker-01 ~]# awk 'BEGIN{print 3.12432623}'
    3.12433

    可以修改OFMT,来自定义数值转换为字符串时的格式:

    [root@docker-01 ~]# awk 'BEGIN{OFMT="%.2f";print 3.99989}'
    4.00

    格式化为整数

    [root@docker-01 ~]# awk 'BEGIN{OFMT="%d";print 3.99989}' 
    3
    [root@docker-01 ~]# awk 'BEGIN{OFMT="%.0f";print 3.99989}'
    4

    printf

    printf format, item1, item2, ...

    格式化字符:

    %c            将ASCII码转换为字符,例如printf "c%" 65将输出A
    %d    %i    转换为整数,直接截断而不会四舍五入,例如:printf "%d" 23.9输出23
    %e    %E    科学计算法方式输出数值
    %f    %F    浮点数方式输出,会四舍五入,例如printf "4.3f%" , 123.4128输出123.413
    %g    %G    输出为浮点数或科学计数法格式。
    %o            将数字识别为八进制,然后转换为10进制,再转换为字符串输出,例如printf "o%" ,8 输出10
    %s        输出字符串
    %x    %X    将数字识别为16进制,然后转换为10进制,再转换为字符串输出,例如:printf "%x" ,16输出10
    
    %%      输出%

    修饰符:均放在格式化字符的前面

    N$      N是正整数。默认情况下,printf的字段列表顺序和格式化字符
            串中的%号顺序是一一对应的,使用N$可以自行指定顺序。
            printf "%2$s %1$s","world","hello"输出hello world
            N$可以重复指定,例如"%1$s %1$s"将取两次第一个字段
    
    宽度     指定该字段占用的字符数量,不足宽度默认使用空格填充,超出宽度将无视。
             printf "%5s","ni"输出"___ni",下划线表示空格
    
    -       表示左对齐。默认是右对齐的。
            printf "%5s","ni"输出"___ni"
            printf "%-5s","ni"输出"ni___"
    
    空格     针对于数值。对于正数,在其前添加一个空格,对于负数,无视
            printf "% d,% d",3,-2输出"_3,-2",下划线表示空格
    
    +       针对于数值。对于正数,在其前添加一个+号,对于负数,无视
            printf "%+d,%+d",3,-2输出"+3,-2",下划线表示空格
    
    #       可变的数值前缀。对于%o,将添加前缀0,对于%x或%X,将添加前缀0x或0X
    
    0       只对数值有效。使用0而非默认的空格填充在左边,对于左对齐的数值无效
            printf "%05d","3"输出00003
            printf "%-05d","3"输出3
            printf "%05s",3输出____3
    
    '       单引号,表示对数值加上千分位逗号,只对支持千分位表示的locale有效
            $ awk "BEGIN{printf "%'d
    ",123457890}"
            123,457,890
            $ LC_ALL=C awk "BEGIN{printf "%'d
    ",123457890}"
            123457890
    
    .prec   指定精度。在不同格式化字符下,精度含义不同
            %d,%i,%o,%u,%x,%X 的精度表示最大数字字符数量
            %e,%E,%f,%F 的精度表示小数点后几位数
            %s 的精度表示最长字符数量,printf "%.3s","foob"输出foo
            %g,%G 的精度表示表示最大有效位数,即整数加小数位的总数量

    sprintf()

    sprintf()采用和printf相同的方式格式化字符串,但是它不会输出格式化后的字符串,而是返回格式化后的字符串。所以,可以将格式化后的字符串赋值给某个变量。

    [root@docker-01 ~]# awk '
    >     BEGIN{
    >         a = sprintf("%03d", 12.34)
    >         print a  # 012
    >     }
    > '
    012
    [root@docker-01 ~]# 

    重定向输出

    print[f] something >"filename"
    print[f] something >>"filename"
    print[f] something | "Shell_Cmd"
    print[f] something |& "Shell_Cmd_Coprocess"
    abc[root@docker-01 ~]# printf abc > "b.txt"
    [root@docker-01 ~]# cat b.txt
    abc[root@docker-01 ~]# 

    [root@docker-01 ~]# printf abc" |& "ls"
    > a
    anaconda-ks.cfg a.txt

    >filename时,如果文件不存在,则创建,如果文件存在则首先截断。之后再输出到该文件时将不再截断。

    awk中只要不close(),任何文件都只会在第一次使用时打开,之后都不会再重新打开。

    [root@docker-01 ~]# awk '{print $2 >"name.txt";print $4 >"name.txt"}' a.txt
    [root@docker-01 ~]# cat name.txt 
    name
    age
    Bob
    28
    Alice
    24
    Tony
    21
    Kevin
    21
    Alex
    18
    Andy
    22
    Jerry
    25
    Peter
    20
    Steven
    23
    Bruce
    27
    [root@docker-01 ~]# cat a.txt 
    ID  name    gender  age  email          phone
    1   Bob     male    28   abc@qq.com     18023394012
    2   Alice   female  24   def@gmail.com  18084925203
    3   Tony    male    21   aaa@163.com    17048792503
    4   Kevin   male    21   bbb@189.com    17023929033
    5   Alex    male    18                  18185904230
    6   Andy    female  22   ddd@139.com    18923902352
    7   Jerry   female  25   exdsa@189.com  18785234906
    8   Peter   male    20   bax@qq.com     17729348758
    9   Steven  female  23   bc@sohu.com    15947893212
    10  Bruce   female  27   bcbd@139.com   13942943905

    >>filename时,将追加数据,文件不存在时则创建。

    print[f] something | Shell_Cmd时,awk将创建一个管道,然后启动Shell命令,print[f]产生的数据放入管道,而命令将从管道中读取数据。

    [root@docker-01 ~]# awk '
    >     NR>1{
    >       print $2 >"name.unsort"
    >       cmd = "sort >name.sort"
    >       print $2 | cmd
    >       #print $2 | "sort >name.sort"
    >     }
    >     END{close(cmd)}
    > ' a.txt
    [root@docker-01 ~]# cat name.unsort 
    Bob
    Alice
    Tony
    Kevin
    Alex
    Andy
    Jerry
    Peter
    Steven
    Bruce
    [root@docker-01 ~]# cat name.sort 
    Alex
    Alice
    Andy
    Bob
    Bruce
    Jerry
    Kevin
    Peter
    Steven
    Tony
    # 例2:awk中构建Shell命令,通过管道交给shell执行
    awk 'BEGIN{printf "seq 1 5" | "bash"}'
    [root@docker-01 ~]# awk 'BEGIN{printf "seq 1 5"}'
    seq 1 5
    [root@docker-01 ~]# awk 'BEGIN{printf "seq 1 5" | "bash"}'
    1
    2
    3
    4
    5

    print[f] something |& Shell_Cmd时,print[f]产生的数据交给Coprocess。之后,awk再从Coprocess中取回数据。这里的|&有点类似于能够让Shell_Cmd后台异步运行的管道。

    stdin、stdout、stderr

    awk重定向时可以直接使用/dev/stdin/dev/stdout/dev/stderr。还可以直接使用某个已打开的文件描述符/dev/fd/N

    例如:

    [root@docker-01 ~]# awk 'BEGIN{print "something OK" > "/dev/stdout"}'
    something OK
    [root@docker-01 ~]# awk 'BEGIN{print "something wrong" > "/dev/stderr"}'
    something wrong
    [root@docker-01 ~]# awk 'BEGIN{print "something wrong" | "cat >&2"}'
    something wrong
    [root@docker-01 ~]# awk 'BEGIN{getline < "/dev/stdin";print $0}'
    
    [root@docker-01 ~]# exec 4<> a.txt
    [root@docker-01 ~]# awk 'BEGIN{while((getline < "/dev/fd/4")>0){print $0}}'
    ID  name    gender  age  email          phone
    1   Bob     male    28   abc@qq.com     18023394012
    2   Alice   female  24   def@gmail.com  18084925203
    3   Tony    male    21   aaa@163.com    17048792503
    4   Kevin   male    21   bbb@189.com    17023929033
    5   Alex    male    18                  18185904230
    6   Andy    female  22   ddd@139.com    18923902352
    7   Jerry   female  25   exdsa@189.com  18785234906
    8   Peter   male    20   bax@qq.com     17729348758
    9   Steven  female  23   bc@sohu.com    15947893212
    10  Bruce   female  27   bcbd@139.com   13942943905
  • 相关阅读:
    mysql 5.7开启sql日志的配置
    Apache显示目录列表及icons目录的问题
    WebGL学习笔记二——绘制基本图元
    java上传文件类型检测
    binlog
    vs2015下C4819该文件包含不能在当前代码页(936)中表示的字符问题解决
    WebGL学习笔记一
    vs2015 debug时出现 C2039“cout”: 不是“std”的成员
    spring boot实现切割分片上传
    springboot自定义类@Resource注入为null的问题
  • 原文地址:https://www.cnblogs.com/liujunjun/p/12395944.html
Copyright © 2020-2023  润新知