• awk知识点总结


    find+xargs+grep+sed+awk系列文章:http://www.cnblogs.com/f-ck-need-u/p/7048359.html


    0.学习资料推荐

    1.awk入门:看视频、找博客或者看《AWK程序设计语言》的第1-3章。

    2.awk进阶:《awk程序设计语言》剩余内容(剩余的我也没看过,哈哈),man awk

    3.awk编程语言:用于掌控awk的语法和方方面面,推荐书籍《gnu awk: Effective AWK Programming

    1. awk简介和基本语法格式

    Awk自动地搜索输入文件,并把每一个输入行切分成字段。许多工作都是自动完成的,例如读取每个输入行、字段分割、存储管理、初始化等。在AWK中不需声明变量数据类型,它内置字符串类型和数值类型。

    一般来说,在CentOS上安装的awk默认是gawk。它的调用格式为:

    awk [OPTIONS] -f program_file [--] filename_list
    awk [OPTIONS] [--] program filename_list
    

    program是awk程序的重中之重,称为awk的程序,它的格式为PATTERN{ACTIONS}。awk每读入一行,都会先与PATTERN做匹配比较,当找到符合条件的数据就执行对应的ACTION。

    其中PATTERN或ACTIONS二者可省一。省略PATTERN时表示对所有行都执行ACTIONS,省略ACTIONS表示对符合条件的行执行默认的print动作。因为二者可省一,所以用大括号{}将ACTIONS部分包围起来,以区分PATTERN和ACTIONS。

    一个简单的例子,输出/etc/passwd中用户shell为/bin/bash的用户名,其中使用"-F"选项指定冒号作为分隔符。

    awk -F':' '$7 == "/bin/bash"{print "who use bash shell: ",$1}' /etc/passwd
    

    其中位置变量$1,$2...为该行的第几个字段,"$0"表示整行。

    如果要输出多个字段,则字段之间使用逗号","分隔,例如{print $1,$5}但输出时,仍默认以空格分隔各输出字段。

    如果action为print $1 $5,则结果会将"$1"和"$5"拼接在一起,因为空格是awk中的拼接字符。例如变量赋值name = "abc" "bcd"等价于name="abcbcd"。其实不算是拼接符,而是因为awk会忽略任何不被引号包围的空白。

    2.print和printf格式化输出

    awk使用print和printf输出数据,不仅可以输出到标准输出中,还可以重定向到文件中,使用管道传递给另一个命令。

    1. print
      将 $0 打印到标准输出。等价于print $0
    2. print expression, expression, …
      打印各个 expression, expression 之间由 OFS 分开, 由 ORS 终止
    3. print expression,expression,… > filename
      文件名filename必须使用双引号包围,否则被当作变量。且文件只会被打开一次。
    4. print expression,expression,… >> filename
    5. print expression,expression,… | command
      将数据传递给系统命令。命令需要使用双引号包围。
    6. printf(format,expression,expression,…)
    7. printf(format,expression,expression,…) > filename
    8. printf(format,expression,expression,…) >> filename
    9. printf(format,expression,expression,…) | command
    10. close(filename), close( command)
      断开 print 与 filename (或 command) 之间的连接
    11. system(command)
      执行 command; 函数的返回值是 command 的退出状态

    如果print或printf的参数列表中含有操作符,则需要使用括号包围,否则容易产生歧义。如:

    print($1, $3) > ($3 > 100 ? "bigpop" : "smallpop")
    print $1, ($2 > $3) 
    

    执行系统命令的方式,可以通过管道的方式,也可以通过system()函数。注意包围命令的引号加的位置。

    awk 'BEGIN{name="ma long shuai";print (1,2,3,4) | "echo " name}'
    awk 'BEGIN{while (("fdisk -l" | getline) >0){print $0}}'
    awk 'BEGIN{system("fdisk -l")}'
    awk 'BEGIN{name="ma long shuai";system("echo " name)}'
    

    printf命令可以输出更格式化的数据。

    printf(format, value1, value2, ... , valueN)
    

    format是一个字符串,包含按字面输出的纯文本,还包含输出格式,格式使用格式说明符"%"描述,后面跟着几个字符,这些字符控制一个value的输出格式。第一个"%"描述value1的输出格式,第二个"%"描述value2的输出格式,依次类推。因此,"%"的数量应该和被输出的value数量一样多。

    例如:

    { printf("total pay for %s is $%.2f
    ", $1, $2 * $3) }
    { printf("%-8s $%6.2f
    ", $1, $2 * $3) }
    

    第一个程序包含了两个要格式化的value,分别是"$1"和"$2 * $3"。这两个value的输出格式分别被"%s"和"%.2f"描述,前者表示按字符串格式输出"$1",后者表示按小数值格式输出"$2 * $3",且小数位占2位。由于printf不自带尾随换行符,因此手动加一个换行符" "。

    第二个程序,"%-8s"表示"$1"按字符串格式输出,但短横线"-"表示要左对齐输出,"8"表示占用8个字符宽度,不足之数在右边空格补齐。"%6.2f"表示按小数格式输出"$2 * $3",且小数位占用2位,总字符数占用6位。注意,小数点也占用一个字符宽度。因此,一个可能的输出值为"123.20"。

    格式说明符"%"后可跟以下几个常见字符:

    • 格式符:
      • %d,%i:十进制整数;
      • %f:显示浮点数;
      • %s:显示字符串;
      • %u:无符号整数;
      • %%:显示%自身。
    • 修饰符:
      • N:显示宽度;N为数值,宽度不足时若为左对齐则右边空格补足,若右对齐则左边空格补足。
      • -:左对齐;
      • +:显示数值正负号。
      • 0:表示以0填充。

    3.输入行的字段分隔符和行分隔符

    使用"-F"选项或设置内置变量"FS"可以控制输入行的字段分隔符,默认分隔符为" "。可通过正则表达式指定分隔符,其实可以认为总是以正则方式指定分隔符。

    以下是几个示例和需要注意的空格分隔符:

    1. -F " ":默认会压缩所有前导空白,包括制表符和空格。
    2. -F " :":当空格后跟一个冒号时作为分隔符。会压缩前导空格,但不会匹配制表符,更不会压缩制表符。
    3. -F "[ ]':只表示一个空格,不压缩任何空白。
    4. -F "|":指定竖线作为分隔符。
    5. -F ",[ ]*|[ ]+":逗号后跟0或多个空白,或者只有1或多个空白时作为分隔符。

    也就是说,当空格写在最前面且不被中括号包围限制的时候,总会忽略前导空格,但不一定能匹配制表符。

    使用内置变量"RS"可以控制输入行的行分隔符,默认为" ",只有遇到行分隔符时才作为"一行"记录被读取。

    将其读作行分隔符不标准,应该读为"记录分隔符"。例如设置以制表符作为记录分隔符。

    RS="	"
    

    记录分隔符变量"RS"只识别第一个字符,若设置为" ",则第二个" "被忽略。但是控制输出记录分隔符的内置变量OFS则可识别多字符。

    可通过设置FS=" ";RS=""使得awk能处理多行记录。但此时,原本的每行数据整体变成一个字段。

    4.BGEIN和END

    BEGIN和END是一个特殊的PATTERN,BEGIN引导的程序是在awk读取第一个文件第一行前要执行的awk程序,END引导的程序是在awk处理完最后一个文件最后一行后要执行的awk程序。通常BEGIN用于输出一个标题,或者初始化一些格式、变量等,END则用于最后的总结性输出。

    所以awk稍微完整一点的格式为:

    BGEIN{ACTIONS}PATTERN{ACTIONS}END{ACTIONS}
    

    刨去BEGIN和END引导的两个程序,中间处理输入文件的程序PATTER{ACTIONS}称为"主输入循环(main input loop)"。在进入主输入循环之前,可以不用提供输入流,但进入主输入循环后,必须提供输入流。

    例如,在开始处理文件前,设置输出报表的头部,在最后输出总共输出了多少行。其中print ""表示输出一个空行。

    BEGIN{print "ID NAME GENDER GENDER";print ""}{print $0}END{print "total num: " NR}
    

    5.数组

    awk的数组和shell的数组类似,都支持数值index的普通数组和字符串index的关联数组,其实数值index仍然会转换成字符串格式的index,所以awk的数组类型都是关联数组。

    数组格式:array_name[index]
    数值赋值:array_name[1]=value1
    引用数组:array_name[1]

    需要注意的是,关联数组的index必须使用双引号包围,例如array_name["ma"],如果写成array_name[ma],则表示使用变量"ma"的值作为index。若"ma"变量未定义,则这会定义一个新的数组array_name[""]

    使用index in array_name的方式可以判断数组array_name中是否有index下标对应的数组元素。如果有,它会返回1,否则返回0。所以判断语句可以如下:

    if ( "ma" in array_name )
    

    其实,判断某个数组变量的值是否为空也可判断该数组元素是否存在,如下。但这有副作用,当该元素不存在时,会创建它。

    if ( array_name["ma"] != "" )
    

    for循环的一种变体:

    for (i in array_name){
        do something about array_name[i]
    }
    

    可以用于遍历数组,其中变量"i"是遍历数组时的index,array_name是数组名。这是以遍历index的方式遍历数组。由于index的顺序随机,所以遍历时顺序也是随机的。当然,遍历数组的方式有多种,以上只是for循环遍历的一种方式。

    使用delete语句可以删除数组中的元素或者删除整个数组。如下:

    delete array_name["ma"]  # 删除array_name中下标为ma的元素
    delete array_name        # 删除数组array_name
    

    6.流程控制语句

    在ACTION中,可以使用流程控制语句。包括但不限于:

    if (expression) statements
    if (expression) statements else statements
    while (expression) statements
    for (expression; expression; expression) statements
    for (expression in array) statements
    do statements while (expression)
    

    还有几个能影响循环的动作:

    break:退出循环。
    continue:退出当前循环,进入下一个循环
    next:读入下一行,并awk程序的顶端从头开始。这个awk程序是PATTERN{action}这部分,不包括BEGIN{action}exit code:直接进入END,若本就在END中,则直接退出awk。如果END中的exit没有定义code,则采用前一个exit的code。
    

    6.1 条件判断语句

    if格式:

    PATTERN {
      if (test_cmd){
          cmd1
          cmd2
          ...
      }
    }
    

    if-else格式为:

    PATTERN {
       if (test_cmd){
          cmd1
          cmd2
          ......
          }
       else
          cmd3
    }
    

    当if或else结构中的命令只有一个,则其内可省大括号,如果超过一个,则需要使用大括号。

    若采用一行书写格式,则如下:

    PATTERN {if (test_cmd){cmd1;cmd2;...}else {cmd3;cmd4...}}
    

    还有if-else if-else格式。

    PATTERN {
        if (test_cmd){cmd_list1}
        else if {cmd_list2}
        else if {cmd_list3}
        else {cmd_list}
    }
    

    还支持多目操作符。

    expression ? action1 : action2
    

    其中"?"和":"还可以继续嵌套。

    6.2 while循环

    结构:

    PATTERN {
      cmd1
      while (test_cmd)
          cmd
    }
    

    当cmd有多个时,使用大括号包围。

    PATTERN {
        cmd1
        while (test_cmd){
            cmd2
            cmd3
            ....
        }
    }
    

    一行书写格式:

    PATTERN{cmd1;while (test_cmd){cmd1;cmd2}}
    

    6.3 do循环

    和while循环类似,地位和shell中的until循环一样。都是至少执行一次命令列表。

    结构:

    PATTERN {
        do{
            cmd1
            cmd2
        } while (test_cmd)
    }
    

    6.4 for循环

    结构大致如下:

    PATTERN {
        for (i=1;i<=10;++i){
        cmd1
        cmd2
        }
    }
    

    for后括号中包括:变量初始值,条件判断和计数器增长表达式。

    7.更完整的awk程序格式和表达式

    更完整的awk程序的语法格式有以下几种:

    BEGIN{actions}
    END{actions}
    expr{actions}
    /regexp/{actions}:可被regexp匹配的行才执行actions
    expr1,expr2{actions}:表示范围,从满足expr1的行开始,到满足expr2的行结束
    

    其中:

    • expr是表达式。
      • 比较操作符有:< <= == != >= > ~ !~
      • 算术操作符有:+ - * / % ^(取幂) **(取幂)。其中**非POSIX标准,不可移植。
      • 赋值操作符有:++ -- += -= *= /= %= ^= **=。awk支持复合赋值,例如FS = OFS = " "表示字段分隔符和输出字段分隔符都被赋值为制表符。
    • /regexp/为正则匹配模式,表示该行能被regexp匹配则为真。还有以下两种匹配表达式,分别表示给定的字符串能(不能)匹配就为真。
      • string ~ /regexp/
      • string !~ /regexp/
    • 还有复合模式的表达式。使用逻辑操作符"&&"、"||"和"!"连接。如$4 == "Asia" && $3 > 500! (NR > 1 && NF > 3)

    awk中字符串和数值数据类型是自动转换的。如果想要得到一个字符串值,可以value ""进行转换,同理,如果想要得到一个数值,可以value + 0

    另外,正则表达式可以不用包围在两个斜杠中。可以将正则表达式赋值给一个变量,然后使用该变量取匹配数据。例如:

    reg="^[0-9]+$"
    $2 ~ reg
    

    甚至直接使用双引号替换斜杠也允许。但不建议使用,因为一个元字符可能需要多个反斜杠来保护,使得看上去极其晦涩。

    8.awk中的变量

    普通变量:给变量赋值时,如果要赋值字符串,则该字符串应该使用双引号包围,特别是包含特殊字符时。赋值数值时无所谓。 字段变量:$1,$2,$3,...,$NF,还有"$0"表示整行内容。另外,可以直接赋值一个新字段或修改字段值。但这都会影响"$0"。同理,修改"$0"也会影响各字段值。
    内置变量:其实可以分为两类,一类是awk内部自动修改的变量,如行数变量NR,一类是内部不会改动的系统变量,如输入字段分隔符变量FS,完全需要手动修改,这类一般都有默认值。

    • ARGV:命令行参数数组。从0开始计数直到ARGC-1。
    • ARGC:ARGV数组元素的个数。
    • FILENAME:当前处理的文件名。
    • FNR:当前处理文件的记录号。(file record num)
    • NR:已处理的总记录数。多个文件时不重置。(record num)
    • NF:当前记录的字段总数。(field num)
    • FS:输入的字段分隔符。默认为空白。(file separate)
    • OFS:输出的字段分隔符。默认为空白。(output record separate)
    • RS:输入流的记录分隔符。默认为" "。(record separate)
    • ORS:输出流的记录分隔符。默认为" "。(output record separate)
    • OFMT:printf输出数值转换成字符串输出时的格式。默认为"%.6g"。
    • CONVFMT:printf输出数值转换成字符串输出时的格式。会被OFMT覆盖。默认为"%.6g"。
    • RLENGTH:被match函数匹配的字符串的长度。
    • RSTART:被match函数匹配的字符串的开始位置。
    • SUBSEP:下标分隔符。默认为"34",ASCII中034代表的是双引号'"'。

    注意,像NR、FNR、RS等的对象是记录(record),而非行。只有当RS=" "时,读取了一行才表示读取了一条记录。

    9.awk中的内置函数

    awk有两类内置函数:算术函数和字符串函数。还支持自定义函数。

    算术函数:

    • cos(x):取x的余弦。
    • sin(x):取x的正弦。
    • sqrt(x):取x的平方根。
    • rand():返回一个随机数r,其中0<=r<1
    • srand(x):设置rand()的种子值为x。种子值相同时,rand()的结果相同。可print srand()输出当前种子值。
    • int(x):取x的整数部分。

    因此,要生成一个范围[1,n]的随机数,使用int(n*rand() + 1),要四舍五入一个数值,使用int(x + 0.5)

    随机数的种子值相同时,rand的结果总是相同。如下两次运行结果,两次结果中,前两个rand()值相同,后两个rand()值不同,因为中间使用了srand()重设种子值。

    awk 'BEGIN{print rand();print rand();srand();print rand();print rand();print srand()}'
      0.237788
      0.291066
      0.109925
      0.983692
      1504560578
    
    awk 'BEGIN{print rand();print rand();srand();print rand();print rand();print srand()}'
      0.237788
      0.291066
      0.96322
      0.670495
      1504560604
    

    字符串函数:建议下面的所有regexp都使用"//"包围。

    • index(str1,str2):返回子串str2在字符串str1中第一次出现的位置。如果没有指定str1,则返回0。
    • length(str1):返回字符串str1的长度。如果未给定str1,则表示计算"$0"的长度。
    • substr(str1,p):返回str1中从p位置开始的后缀字符串。
    • substr(str1,p,n):返回str1中从p位置开始,长度为n的子串。
    • match(str1,regexp):如果regexp能匹配str1,则返回匹配起始位置。否则返回0。它会设置内置变量RSTART和RLENGTH的值。
    • split(str1,array,sep):使用字段分隔符sep将str1分割到数组array中,并返回数组的元素个数。如果未指定sep则采用FS的值。因此该函数用于切分字段到数组中,下标从1开始。
    • sprintf(fmt,expr):根据printf的格式fmt,返回格式化后的expr。
    • sub(regexp,rep,str2):将str2中第一个被regexp匹配的字符串替换成rep,替换成功则返回1(表示替换了1次),否则返回0。注意是贪婪匹配。
    • sub(regexp,rep):将"$0"中第一个被regexp匹配的字符串替换成rep,替换成功则返回1,否则返回0。注意是贪婪匹配。
    • gsub(regexp,rep,str2):将str2中所有被regexp匹配的内容替换成rep,并返回替换的次数。
    • gsub(regexp,rep):将"$0"中所有被regexp匹配的内容替换成rep,并返回替换的次数。
    • toupper(str):将str转换成大写字母,并返回新串。
    • tolower(str):将str转换成小写字母,并返回新串。

    关于替换函数sub和gsub,可以在替换字符串rep中使用"&"符号表示反向引用,引用的是整个被匹配的部分。

    awk 'BEGIN{
        print index("banana","na")
        print length("banana")
        print match("banana","na.*")
        print toupper("banana")
        print substr("banana",3)}' 
    3
    6
    3
    BANANA
    nana
    
    awk 'BEGIN{str1="x&x";str2="banana"
            print sub(/a.*n/,str1,str2)
            print str2}' 
    1
    bxananxa
    
    awk 'BEGIN{
        print match("banana",/a.*n/)
        print RSTART,RLENGTH}'
    2
    2 4
    
    awk 'BEGIN{print sprintf("hello %i world %5s","123","abc")}'
    hello 123 world   abc
    
    awk 'BEGIN{
        name="Ma long shuai"
        split(name,myname)
        for (i in myname){
            print myname[i]}
        }'
    Ma
    long
    shuai
    

    纵观上述字符串函数,没有一个函数可以将匹配成功的字符串输出出来。但借助match()和RSTART、RLENGTH可以实现。

    例如,取出"Ma:long:shuai"中的"long"并输出。

    awk 'BEGIN{
        name="Ma:long:shuai"
        if (match(name,/:[^:]*:/)){
            print substr(name,RSTART+1,RLENGTH-2)}}'
    long
    

    10.自定义函数

    function name(parameter-list) {
        statements
    }
    

    函数中的变量不影响函数外的变量,但可以使用外部变量。参数列表使用逗号分隔,这些参数只在函数内部生效。

    可以在awk的引号内任意位置处定义函数(即使是BEGIN之前或END之后),且函数的调用位置可以在函数的定义位置之前。但注意,函数必须不能定义在BEGIN或主输入循环或END内部,否则自定义函数的大括号会和包围action的大括号冲突而报错。即如下(1)-(4)处位置可定义定义函数,在任意位置处调用函数。

    awk '(1)BEGIN{ACTIONS}(2)PATTERN{ACTIONS}(3)END{ACTIONS}(4)'
    

    在函数的statements中,可以使用return expression语句,表示函数的返回值。

    例如,创建一个"向字符串指定位置处插入一个字符"的函数。

    awk 'function insert(STRING, POS, INS) {
        before_tmp = substr(STRING, 1, POS)
        after_tmp = substr(STRING, POS + 1)
        return before_tmp INS after_tmp
    }
    BEGIN{print insert("banana",3,"x")}'
    

    11.getline函数

    getline函数用于从文件、标准输入或管道中读取数据,并按情况设置变量的值。getline可以自动不断的加载下一行。如果能读取记录,则getline的返回值为1,遇到输入流的尾部时,返回值为0,不能读取记录(如文件没有读取权限、文件不存在)时,返回值为“-1"。

    其中:

    • getline:会从主输入文件中读取记录。会同时设置$0,NF,NR,FNR。
    • getline var:会从主输入文件中读取记录,并将读取的记录赋值给变量var。会同时设置var,NR,FNR。
    • getline <file:从外部文件file中读取记录。同时会设置$0,NF。
    • getline var <file:从外部文件file中读取记录,并将读取的记录赋值给变量var。会同时设置var。
    • cmd | getline:从管道中读取记录。会同时设置$0,NF。
    • cmd | getline var:从管道中读取记录,并将读取的记录赋值给变量var。会同时设置var。

    也就是说:

    1. 当getline从非主输入文件读取记录时,不会设置NR和FNR;
    2. 当getline后没有给定变量var时,会将读取的记录赋值给$0,于是会同时设置NF并切分成字段;否则将读取的记录赋值给变量var,不会设置NF切分字段。

    仍然注意,从外部文件file中读取记录时,需要使用双引号包围文件名,否则被当成awk中的变量。

    例如,执行Linux下的who命令并传递给getline读取,每读取一行记录,变量n自增1。

    while ("who" | getline)
    n++
    

    将Linux命令date的结果保存到awk的变量date中。

    "date" | getline date
    

    当写成循环时,如:

    while (getline <"file"){
        cmd...
    }
    

    这是不安全的,因为当无法读取file时,返回值为"-1",而while循环的判断条件是0和非0,所以"-1"也会进入死循环。所以,安全的写法为:

    while (getline <"file" >0){
        cmd...
    }
    

    12.向awk传递变量

    awk很重要且必备的能力是接受外界的变量,例如shell中的变量,shell中命令执行的结果,或者是在开始执行awk前应该初始化的变量。

    例如,在shell中定义一个变量name,传递给awk使用。

    awk -v awk_name="$name" 'BEGIN{print awk_name}' 
    Ma longshuai
    

    有三种方式可以向awk传递变量:

    1.将待传递变量当作文件名被awk解析。awk识别后发现是赋值语句,就认为其是变量传递。变量赋值语句必须定义awk program之后。此法定义的变量不可在BEGIN中使用,因为它是被当成文件解析的,只有在需要读取主输入文件的时候才会被解析。

    awk 'BEGIN{}PATTERN{print var1,var2,var3}' var1=value1 var2=value2 file1 var3=value3 var1=value4 file2
    

    在上面的语句中,当awk执行完BEGIN程序后,准备读取主输入,于是开始解析program后的输入文件。解析时发现,var1和var2都是赋值语句,于是当成变量处理,当读取到file1时,发现只有一个参数,则当作输入文件,于是开始处理该文件。在处理file1时,var1和var2都是有效的,但var3还未赋值,因此var3无效。当处理完file1后,继续解析下一个主输入文件,此时var3被赋值,并开始处理file2。在处理file2时,var1、var2和var3都是有效的,但var1被新值覆盖。

    此外,还可以将shell命令的结果赋值给这些预定义变量。如下展示了几种变量定义的方式:

    name="Ma longshuai"
    awk 'program' OFS=":" var1="$name" var2="`echo Ma longshuai2`" var3="Ma longshuai3" var4=Malongshuai4 filename
    

    不仅可以定义普通变量,还可以定义内置变量(如上OFS)。注意加引号的方式:为了安全,应该对所有赋值语句的value部分加上双引号,除非所赋的值不包含特殊字符。所以,如果上面的var1赋值语句写成var1=$name,将被awk解析成var1=Ma longshuai,于是var1的值为Ma,主输入文件为longshuai。

    2.使用"-v"选项传递。变量赋值语句必须定义在awk program之前。这种方法定义的变量可以在BEGIN程序中使用。

    除了定义在program之前,定义方式同上。每定义一个变量,都需要使用一个"-v"选项。如:

    name="Ma longshuai"
    awk -v OFS=":" -v var1="$name" -v var2="`echo Ma longshuai2`" -v var3="Ma longshuai3" 'program' filename
    

    3.通过参数数组ARGV的方式。

    ARGV是内置的数组变量。awk内部会将命令行切分,并按规则将各参数存放到ARGV数组中,数组下标从0开始,这是awk中唯一下标从0开始的数组。在存放到ARGV时,所有的选项和program会被忽略。

    每存储一个数组变量,特殊变量ARGC的值增加1。因此ARGC的值代表的是参数的个数。所以,数组变量从ARGV[0]到ARGV[ARGC-1]。

    可使用类似下面的循环来遍历ARGV数组。

    awk -F "	" -v var1="value1" 'BEGIN{
            for(i=0;i<ARGC;++i){
                print "ARGV[" i "]: " ARGV[i]
            }
            print "ARGC: " ARGC
        }' "a" "b" "v=1" file 
      ARGV[0]: awk
      ARGV[1]: a
      ARGV[2]: b
      ARGV[3]: v=1
      ARGV[4]: file
      ARGC: 5
    

    注意,ARGV[0]存储的是awk命令,"-F"和"-v"选项都没有存储到ARGV中。

    ARGC和ARGV数组变量的值都可以手动修改。命令行分割存储完成之后,开始处理BEGIN,再处理主循环输入。因此,在BEGIN中修改ARGV中输入文件对应的值,可以改变awk所读取的输入文件,若将其设置为空,则该数组变量直接被跳过,也就不再读取该输入文件。

    需要注意的是,当增加ARGV元素时,必须同时递增ARGC的值,因为awk是根据AGRC来读取ARGV的。同理,只增加ARGC的值,将导致新建ARGV数组元素,且这些新元素的值为空。也因此,如果减小ARGC的值,将导致无法访问超出ARGC-1边界的ARGV元素。

  • 相关阅读:
    129 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 03 饿汉模式 VS 懒汉模式 02 懒汉式的代码实现
    128 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 03 饿汉模式 VS 懒汉模式 01 饿汉式的代码实现
    127 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 02 单例模式概述 01 单例模式的定义和作用
    126 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 01 设计模式概述 01 设计模式简介
    125 01 Android 零基础入门 02 Java面向对象 05 Java继承(下)05 Java继承(下)总结 01 Java继承(下)知识点总结
    leetcode-----121. 买卖股票的最佳时机
    leetcode-----104. 二叉树的最大深度
    Json串的字段如果和类中字段不一致,如何映射、转换?
    Mybatis-Plus的Service方法使用 之 泛型方法default <V> List<V> listObjs(Function<? super Object, V> mapper)
    模糊查询
  • 原文地址:https://www.cnblogs.com/f-ck-need-u/p/7509812.html
Copyright © 2020-2023  润新知