zoukankan      html  css  js  c++  java
  • Linux文本处理三剑客之awk学习笔记09:ARGC和ARGV等

    简介

    ARGC和ARGV都是awk的预定义变量。

    ARGC存储了awk的CLI参数数量(Argument Count);ARGV(Argument Value)是一个数组变量,虽然是关联数组不过其下标是从0开始的数值(当然,内部识别为字符串),存储了这次awk的CLI执行中的每个参数。

    # awk -va=1 -F: 'BEGIN{print ARGC;for(i in ARGV){print i,ARGV[i]}}' b=3 a.txt b.txt
    4
    0 awk
    1 b=3
    2 a.txt
    3 b.txt

    通过该示例我们可以发现。数组的参数包含了awk命令本身(且它是数组下标为0的第一个参数),选项型参数和非选项型参数(这块不懂请参见这里)。

    ARGV[0] ==> "awk"
    ARGV[1] ==> "b=3"
    ARGV[2] ==> "a.txt"
    ARGV[3] ==> "b.txt"

    因此ARGC的值就为4,即ARGC也是ARGV的数组长度(length(ARGV))。ARGV不包含选项以及具体的awk代码。

    -va=1
    -F:
    'BEGIN{print ARGC;for(i in ARGV){print i,ARGV[i]}}'

    ARGV的元素数量/长度只有在awk执行的开始时等于ARGC,在代码执行的过程中我们可以对这两个预定义变量进行修改。

    ARGV和ARGC的内容决定了本次awk执行过程中如何对待参数,伪代码形似如下:

    for(i=1;i<ARGC;i++){
        ... process ARGV[i] ...
    }

    只减小ARGC的值会导致原本应该被读取到的参数丢失,即可能出现尾部文件无法被读取的情况。

    awk '{print}' a.txt b.txt
    awk 'BEGIN{ARGC--}{print}' a.txt b.txt

    只增加ARGC的值不会对结果产生任何影响。

    awk 'BEGIN{ARGC++}{print}' a.txt b.txt

    如果我们对ARGV中的元素进行新增或者删除,那么需要同时改变ARGC的值才会使得结果是我们所期待的。

    awk 'BEGIN{ARGV[ARGC]="c.txt"}{print}' a.txt b.txt
    awk 'BEGIN{ARGV[ARGC++]="c.txt"}{print}' a.txt b.txt

    在这里,3个文件,原本ARGC的值应该是4,我们手动设定为了3,因此只会读取a.txt和b.txt。

    awk 'BEGIN{ARGC=3}{print}' a.txt b.txt c.txt

    如果我们将ARGV[1](即a.txt)删除或者置空,那么awk依然只会读取2个参数(不包括awk命令本身),第一个参数是空字符串,第二个参数是b.txt。并不会因为少掉了一个参数,该位置就被后续的给顶替了。c.txt是一直无法被读取的。也就是说空字符串参数也可以被读取。

    awk 'BEGIN{ARGC=3;delete ARGV[1]}{print}' a.txt b.txt c.txt
    awk 'BEGIN{ARGC=3;ARGV[1]=""}{print}' a.txt b.txt c.txt
    # awk 'BEGIN{print ARGC}' a.txt b.txt c.txt ""
    5

    另外再来看几个预定义变量。

    FILENAME:顾名思义,文件名,存储当前正在处理的文件的文件名。

    awk 'FNR==1{print FILENAME}' a.txt b.txt c.txt

    ARGIND:参数的索引值(Argument Index)。存储你当前正在处理的文件在ARGV中的索引值。因此,当awk正在处理的参数刚好是文件的时候,“FILENAME==ARGV[ARGIND]”总是会返回true。

    ENVIRON:这是一个数组变量,保存了shell的环境变量。

    ENVIRON["SHELL_ENV"]    # 这里的SHELL_ENV要替换成shell下具体的环境变量。
    # echo $SHELL
    /bin/bash
    # awk 'BEGIN{print ENVIRON["SHELL"]}'
    /bin/bash
    # echo $HOME
    /root
    # awk 'BEGIN{print ENVIRON["HOME"]}'
    /root

    ARGC和ARGV的妙用

    当我们使用awk处理文件时,如果文件的权限不足,或者文件不存在,那么awk就会报错并且退出,不再处理报错文件的后续文件。

    注意:我这里使用了普通用户alongdidi来测试,root用户权限较大,即使权限000依然可读取。

    $ ls -l {a,aa,aaa}.txt
    ls: cannot access aaa.txt: No such file or directory
    ---------- 1 alongdidi alongdidi   0 Jan 26 16:44 aa.txt
    -rw-rw-r-- 1 alongdidi alongdidi 566 Jan 26 16:47 a.txt
    $ awk '{print}' {a,aa,aaa}.txt
    ID  name    gender  age  email          phone
    ... ...
    awk: cmd. line:1: fatal: cannot open file `aa.txt' for reading (Permission denied)
    # 到这里就结束了,并不会处理aaa.txt
    $ awk '{print}' {a,aaa}.txt
    ID  name    gender  age  email          phone
    ... ...
    awk: cmd. line:1: fatal: cannot open file `aaa.txt' for reading (No such file or directory)

    我们可以使用ARGC和ARGV来将那些无法正常读取的文件从待处理的文件中剔除。

    思路如下:

    • 必须在main之前就修改待处理的文件,因此代码应写在BEGIN中。
    • 结合getline的返回值特性来判断文件的可读性,getline正常的文件要记得关闭。
    • 参数可能会是选项型参数(变量赋值var=val)或者标准输入(-和/dev/stdin),这类情况需要排除。
    • 由于是删除ARGV的元素,因此不要减小ARGC的值不然可能会造成位于尾部的正常文件无法被处理。
    $ cat ARGCandARGV.awk 
    BEGIN{
        for(i=1;i<ARGC;i++){
            if(ARGV[i]~/[[:alpha:]_][[:alnum:]_]*=.*/ || ARGV[i]=="-" || ARGV[i]=="/dev/stdin"){
                continue
            }else if((getline var < ARGV[i])<0){
                delete ARGV[i]
            }else{
                close(ARGV[i])
            }
        }
        for(i=1;i<ARGC;i++){
            print i,ARGV[i]
        }
    }

    由普通用户alongdidi执行看结果。

    $ awk -f ARGCandARGV.awk a=3 {a,aa,aaa}.txt - /dev/stdin
    1 a=3
    2 a.txt
    3 
    4 
    5 -
    6 /dev/stdin

    变量赋值、标准输入被跳过,保留在ARGV中。可正常读取的文件a.txt被保留,无权限读取(aa.txt)和不存在的文件(aaa.txt)被移出ARGV。

    因此此可再次执行代码就不会报错了。用户也可以把main代码写在-f指定的文件中,我直接使用-e指定了。

    $ awk -f ARGCandARGV.awk -e '{print}' a=3 {a,aa,aaa}.txt - /dev/stdin
    1 a=3
    2 a.txt
    3 
    4 
    5 -
    6 /dev/stdin
    ID  name    gender  age  email          phone    # 由于我们在代码中有正确使用close(),因此文件在打印时依然是从首行开始。
    ... ...
  • 相关阅读:
    华为徐直军第一次非主场演讲,信息量很大
    智慧城市行业领军企业一览表
    【Python】+Django框架使用
    【Python】+pip超时
    【Python】+web应用开发/界面/Django/Flask
    【Java】+【JSON】+对比两个json对象是否完全一样
    【数据库】+多表查询
    【Java】+MD5生成
    【Java】+操作csv文件
    【Java】+反射1+获取属性/成员变量 的名称及类型
  • 原文地址:https://www.cnblogs.com/alongdidi/p/awkARGCandARGV.html
Copyright © 2011-2022 走看看