zoukankan      html  css  js  c++  java
  • sed与awk

    ftp://ftp.oreilly.com/published/oreilly/nutshell/sedawk_2

     有3种方法可以在命令行上放多个指令:

    1. 用分号分隔指令
    sed 's/ma/, mutil/;s/zhao/zzzz/'
    2, 使用-e
    sed -e 's/fs/fsgf/' -e 's/dfdg/dhs/'
    3. 使用分行指令功能
        sed '
    s/g/dfgh/
    s/zz/dfgf/
    s/CA/,FG/' list

    4. sed / awk -f scriptfile file

    sed和awk指令结构相同,都是由模式和过程组成,并且都可以使用多个指令。在awk中语句和函数取代了一个或两个字符组成的命令序列,例如print语句打印输出。

     awk出错信息

    1. 没有用大括号{},将动作括起来。
    2. 没有用单引号' '将指令括起来。
    3. 没有用斜杠//将正则括起来。

     awk引用外部变量http://www.xuebuyuan.com/105422.html

    awk在使用某个变量前不必先赋值,因为awk将变量复制为空字符串。

    正则相关

    1. 在awk中点号.可以匹配换行。
    2. [...]方括号中^表示取反,即取其他字符,awk中包括换行。第一个字符为右括号]或-时表示它是成员,同事存在时]放第一个,-放最后。其他元字符在方括号中失去原来的含义,反斜杠在awk的方括号中仍有特殊意义,可以转义连字符或方括号,如[a]1]。
    3. {n,m}在有些awk中仍然不能使用。awk支持egrep中的大多数正则用法。扩展正则:+, *, |, (), {},
    4. .[!?;:,".] . 第一个和最后一个点是通配。
    5.
    POSIX字符类及意义:  必须出现在方括号表达式中,如[[:upper:]]
    [:upper:]  表示大写字母[A~Z]
    [:lower:]  表示小写字母[a~z]
    [:digit:]  表示阿拉伯数字[0~9]
    [:alnum:]  表示大小写字母和阿拉伯数字[A~Za~z0~9]
    [:space:]  表示任何产生空白的字符,包括空格或Tab键等
    [:alpha:]  表示大小写字母[A~Za~z]
    [:cntrl:]  表示键盘的控制按键,包括Tab、Del等按键
    [:graph:]  表示除了空格符(空格键与Tab键)外的其他所有按键
    [:print:]  表示任何可以被打印出来的字符
    [:xdigit:] 表示十六进制数字[0~9A~Za~z]
    [:blank:]  表示空格键与Tab键
    [:punct:]  表示标点符号,包括:" ' ? ! ; : # $... 
    基本sed命令
    sed命令可以指定0个,1个,或2个地址。每个地址都是一个描述模式,行号或者正则表达式。 注: 行号计数器不会因为多个输入文件重置。 如果指定了逗号分隔的两个地址,那么命令应用于第一个地址的第一行和它后面的行,直到匹配第二个地址的行(包括此行)。第二个地址从第一个地址之后开始寻找。第一个地址启用动作,第二个地址禁用动作,无法先行决定第二个地址是否会匹配,一旦匹配了第一个地址,这个动作就应用与这些行。直至第二个地址匹配。 如果地址后有感叹号
    !,那么命令将应用与不匹配该地址的所有行。 /^.TS/,/^.Te/!d 删除这些行之外的所有行。

    $可以表示最后一行,但不应该和正则表达式中的$混淆。正则必须封闭在斜杠(/)中。 /^$/d

    命令后添加空格会产生语法错误,命令的结束必须在行的结尾处。
    如果命令之间用分号分隔,那么可以讲多个sed命令放在同一行。 n;d在结构上是正确的,然后在n后面放置一个空格会导致语法错误,而在d前面放置一个空格是可以的。不提倡在同一行放置多个命令。
    分组命令
    linux sed命令详解 http://www.cnblogs.com/ggjucheng/archive/2013/01/13/2856901.html
    http://www.cnblogs.com/stephen-liu74/archive/2011/11/17/2245130.html
    sed使用大括号{}将一个地址嵌套在另一个地址中,或者在相同的地址上引用多个命令。 如果想指定行的范围,然后再这个范围内再指定另一个地址,则可以嵌套地址。注:左大括号必须在行末,而且右大括号本身必须单独占一行。要确保在大括号之后没有空格。
    /^.TS/,/^.Te/{          注:大括号可以在同一行上,命令之间用分号隔开。sed -n '/root/{n;d}' /etc/passwd #将匹配root行的下一行删除
    /^$/d  #命令在大括号内可以缩进
    s/zhaodfd/.ps 8/
    s/^.vs 2/.ps 10/  #替换部分的点号不必转义。
    }
    替换
    [address]s/pattern/replacement/flags
    flags可以是:n(第n次), g, p, W file(写入文件)
    分隔符可以是任意字符,出现3次并且在replacement之后是必须的。s!/home/z!/home/x!
    在replacement部分只有下列字符有特殊含义:
    &:正则匹配的整个内容
    : 第n个字符串,在pattern中用(。。。)指定。
    :转义字符。&符号,反斜杠,定界字符,换行都可以用转义。因此除了正则中的元字符外,sed的替换部分也有元字符。
    echo 'zh xng' | sed 's/ /    #转义换行,&    注: 上换行用
    也可以
    xxxxxxxx      #换行
    yyyyyyyyyy/'
    注: 如果匹配同一行的多个替换命令,那么该行的多个备份就会被打印或者写到文件中。
    删除
    d,删除整行,而不是匹配部分。一旦执行删除命令,那么在“空的”模式空间中就不会再有命令执行。删除命令会导致读取新的输入行,而编辑脚本则从头开始新的一轮(这一行为和next命令相同),UNIX文件写到:不允许在被删除的行上进一步操作。
    追加,插入,更改
    [line-address]a\, [line-address]i\, [address]c. 命令后面接反斜杠或者空格都可以。但是用反斜杠才是正路,很多书籍和命令详解都用的是反斜杠。
    [root@tg output]# echo -e 'zhao xiang dsgf fsad  ssdf sdgfdfsgd' | sed '/zhao/a ni hao'  
    #斜杠后面的任何内容追加在匹配行之后,即使是命令 /xian/i first line也被当做文本。空格也原样追加。
    [root@tg output]# echo -e 'zhao xiang dsgf fsad ssdf sdgfdfsgd' | sed '/zhao/a ni hao' zhao xiang dsgf fsad ssdf sdgfdfsgd ni hao [root@tg output]# echo -e 'zhao xiang dsgf fsad ssdf sdgfdfsgd' | sed '/zhao/a ni hao' #如果命令后面接空格,则多余的空格被忽略了。 zhao xiang dsgf fsad ssdf sdgfdfsgd ni hao
    正确的做法应该是在命令后用反斜杠,然后追加的文本单独起一行,文本中有换行用 或者用反斜杠换行。最后一行不用反斜杠。 这样即使有多个命令也不会有问题。
    [root@tg output]# echo 'test  zhao xiang ' | sed '/^test/a
    --->this is a example
    > /xiang/i
    > first line'
    first line
    test  zhao xiang 
    --->this is a example
    [root@tg output]# 
    [root@tg output]# echo 'test  zhao xiang ' | sed '/^test/i
    > '
    
    test  zhao xiang 
    [root@tg output]#插入空行,让命令后面的行为空
    更改命令清除模式空间,与删除命令有同样的效果,在更改命令之后的命令不应该被提供。
    插入和追加命令不影响模式空间的内容。所提供的文本将不匹配后续命令的任何地址,那些命令也不影响该文本,不管什么更改改变了模式空间,所提供的文本仍然会正确输出。即使模式空间不是那样的,而且,所提供的文本不参与sed的内部计数器

     列表命令

    列表命令l 用于显示模式空间的内容,并将非打印字符显示为两个数字的ASCII码。类似于vi的列表命令(:l)

    sed -n -e "l" test
    因为列表命令立即产生输出,所以抑制默认的输出,否则会得到行的重复。

     转换

    [address]y/abc/xyz/ 影响模式空间的所有内容

    打印行号

    [line-address]= , 这个命令不能对一个范围的行进行操作。

    下一步

    [address]n , 输出模式空间的内容(如果没有抑制输出)然后读取下一行,替换模式空间,而不返回到脚本的顶端,之前的命令应用于当前行,后续命令应用于替换之后的内容。

    读和写

    [line-address]r file, [address]w file . 读命令将由fiel指定的文件确定的行之后的内容读入模式空间,不能对行范围操作。写命令将模式空间的内容写入文件。文件名之前必须有空格,空格后到换行符前的内容都是文件名。 文件不存在也不会报错。如果一个脚本有多个命令写到同一个文件中,那么每个命令的内容将追加到文件中。而且每个脚本最多只能打开十个文件。

    使用-n可以阻止模式空间的行被自动输出,但是读命令的结果仍然转到标准输出。

    退出

    退出命令[line-address]q, 会使sed停止读取新的输入行,并停止将他们送到标准输出。它只适用于单行地址,一旦找到匹配行,脚本就结束。

    awk

     echo a b c | awk 'BEGIN {one = 1;two=2} {print $(one+two)}'  #输出c

     分隔符:

    awk -F" " 或者 BEGIN{ FS=","} ,可以使用正则。 输出分隔,OFS=" ",OFS可以重新定义为一系列字符。

    print $1,$2  逗号使个字段之间用空格隔开。不用逗号则各字段连在一起,print $1 "," $2  ,输出"$1逗号$2"。 输出域的分隔符默认是一个空格,保存在OFS中。如$ awk -F: '{print $1,$5}' test,$1和$5间的逗号就是OFS的值。

    awk中RS,ORS,FS,OFS区别与联系

    变量

    awk中可以使用转义序列。变量,运算符,表达式,控制结构和C相似。变量无需加$符号,未初始化的变量为空或0。  每个变量有字符型值和数值型值,不包含数字的字符串为0.

    空格是字符串连接操作符。Z="hello" "world"

    赋值操作符:++,--,[+-*/%^]= ,**=  ,关系操作符:>,<,>=,<=,==,!=, ~, !~ 匹配/不匹配。逻辑操作&&,||,! ,!可以用于字符串,判断字符串是否非空。 见awk编程: 复合表达式,都和C类似。 匹配可以用于字符串变量也可用于/regex/. name=root; $1 ~ name 或者 $1 ~ /root/  貌似用正则的地方也可以用字符串。

    in操作符可以判断某个下标是否在数组中。条件操作 expr ? action1 : action2

    改变当前记录的字段数NF的值会有副作用,增加NF的值会创建新的空字段,并重新建立$0,字段由OFS的值分隔。

    变量名    变量内容
    ARGC    命令行参数的数量。
    ARGIND    命令行正在处理的当前文件的AGV的索引。
    ARGV    命令行参数数组。
    CONVFMT    转换数字格式。
    ENVIRON    从shell中传递来的包含当前环境变量的数组。
    ERRNO    当使用close函数或者通过getline函数读取的时候,发生的重新定向错误的描述信息就保存在这个变量中。
    FIELDWIDTHS    在对记录进行固定域宽的分割时,可以替代FS的分隔符的列表。
    FILENAME    当前的输入文件名。
    FNR    当前文件的记录号。
    FS    输入分隔符,默认是空格。
    IGNORECASE    在正则表达式和字符串操作中关闭大小写敏感。
    NF    当前文件域的数量。
    NR    当前文件记录数。
    OFMT    数字输出格式。
    OFS    输出域分隔符。
    ORS    输出记录分隔符。
    RLENGTH    通过match函数匹配的字符串的长度。
    RS    输入记录分隔符。
    RSTART    通过match函数匹配的字符串的偏移量。
    SUBSEP    下标分隔符。
    [zhangy@localhost test]$ awk 'BEGIN{OFS="|";}{print $1,$2}' test1
     111|222
     333|444
     555|666
    [zhangy@localhost test]$ awk 'BEGIN{OFS="|";}{print $1 OFS $2}' test1
     111|222
     333|444
     555|666
    [zhangy@localhost test]$ awk 'BEGIN{OFS="|";}{print $0}' test1
     111 222
     333 444
     555 666
    [zhangy@localhost test]$ awk 'BEGIN{OFS="|";}{NF=NF;print $0}' test1
     111|222
     333|444
     555|666
    为什么第二种方法中的OFS生效呢?个人觉得,awk觉查到列有所变化时,就会让OFS生效,没变化直接输出了。 可以设置$1=$1

    可以用NF来引用最后一个字段。 $NF,$(2+3)

    多行记录

    FS=" "; RS="" 记录分隔符为空字符串,代表空行。 

    OFS=" "; ORS=" "; 

    格式化打印 

    printf(format,[args]) , 圆括号可选。 Shell常用技巧(五) awk编程 , Awk学习笔记 ,Shell编程-awk

    format的格式:%-width.precision specifier , 数值的默认precision为"%.6g" ,默认精度可以通过设置系统变量OFMT来改变,如"%.2f"。

    向脚本传递参数

    awk引用外部变量

    控制结构,和C相同,if [else if] else, for(;;),while(){}, do{}while(),break,continue

    next导致读入下一个输入行,并返回到脚本底部,可以避免当前输入行执行其他操作  。 exit是输入主循环退出,转到END规则。没有END或者在END中用exit则终止脚本的执行。exit可以使用一个表达式作为参数,作为awk的退出状态返回。

    数组

    a[sub]=value,不必指明数组大小,awk的所有数组都是关联数组,下标可以使字符串和数字。

    遍历:for( var in arr )do something with arr[var] ,访问顺序随机。 eg: arr[grade]++ ,即使grade最初不在数组arr中。

    重要的是记住awk中的所有下标都是字符串型的,即使使用数字作为下标,awk自动将它们转为字符串,当使用浮点数做下标时向字符串转可能会有影响。

    成员测试: item in array, 存在返回1,否则返回0。   awk应用小结(所有命令行均经调试) 

    split()创建数组: n=split(str, array, sep), 返回元素个数,sep可以是正则。

    删除数组元素: delete array[sub]

    模拟多维数组: array[3,2], 成员测试时下标必须放置在圆括号中。 if((i,j) in array)。 多维数组的下标分别解释为单独的字符串,用系统变量SUBSEP连接,默认为“34”。

    多维数组循环: for(item in array) split(item,sub,SUBSEP). 必须用split()函数来访问单独的下标分量,split使用下标item创建数组sub。

    系统变量的数组: 命令行参数ARGV,下标0到ARGC-1,不包括脚本名和选项,ARGV[0]是'awk'。  ENVIRON环境变量数组,其中下标是环境变量的名字。

     可以向ARGV数组添加元素,但是注意要同时增加ARGC的值,awk使用ARGC的值来得到ARGV中有多少元素可以处理。如果ARGV的元素值是一个空串awk将跳过它。

    函数

    数学函数...

    取整int(),print int(100/3)

    rand()生成0到1之间的浮点随机数。srand()为随机数发生器设置一个种子数或者起点数,srand([x]),不带参数是使用当前时间。

    字符串函数:字符串的起始位置为1,

    sub(regex,s,[t=$0]),替换第一个出现的,成功返回1否则返回0. gsub(regex,s,[t=$0])返回替换的个数。正则用//包围。 直接改变指定字符窜,返回的不是替换后的字符串。 和sed一样,替换字符串中的&将被正则匹配的字符串代替。&代表"&",在字符串中必须输入两个\。

    index(s,t)返回t在s中的位置,没有指定s返回0. length([s=$0])。

    match(s,regex),正则用//包围,返回regex出现的起始位置,若没有,返回0。设置RSTART和RLENGTH的值。可以用在while循环中,但在每次循环中要改变已匹配的[RSTART..RSTART+RLENGTH]部分,使下次循环是不再匹配已匹配的部分。   注意sub的正则在前面,match的正则在后面。

    split(s,arr,sep)返回元素个数,没有sep则用FS。

    sprintf(fmt,ecpr),  substr(s,p,[n]),子串p开始最大长度为n。 tolower(s), toupper(s)。

    lowerChars="abcdef..."; f=substr($1,1,1); if(i=index(lowerChars,f)) $1=substr(upperChars,i,1) substr($1,2) #首字母改大写

    awk 用法 Awk 命令学习总结 Linux Shell常用技巧(五) awk编程 awk使用手册

    自定义函数

    function name(arg1,arg2,..){ statements }  return 语句返回。

    函数参数都是局部变量。 函数体重定义的变量默认为全局变量。 可以将局部的临时变量列在参数列表末尾。 在参数列表中参数按顺序接受传递来的值。其他的参数初始化为空串。

    高级主题

    getline函数用于从输入中读取另一行。也能处理来自文件和管道的输入。next语句也是读取下一行,但是next语句将控制传递到脚本的顶部。getline函数得到下一行但不改变脚本的控制。返回值,1:读取一行, 0:到达文件末尾, -1:遇到错误。 尽管被称为一个函数,但是它类似于一个语句,且不能写成getline()。   while(getline > 0) cmd=amd $0

    当读取新行后,getline将它赋给$0,并将它分解成字段,同时设置NF,NR,FNR。因此新行变成当前行。如果需要,可以用getline读取一行并将它赋给一个变量从而避免改变$0。 getline var

    从文件中读取:while( (getline < "data") > 0 ) ,"data"是一个文件名字符串。加括号是为了防止混乱。

    标准输入读取: getline [var] < "-"

    将输入赋值给变量:getline var 不是var = getline, 对$0没有影响。输入行没有被分解为字段,对NF没有影响。但它递增了记录计数器NR, FNR。

    从管道读取: "who an i" | getline .将命令的结果赋给$0,同时设置系统变量。$0被改变,$1,NF等变量肯定都跟着改变,它也是根据FS来分隔字段,所以要注意改变FS的地方。 即使$0不改变,NR, FNR也会改变。

    当包含多个输入行时getline一次读取一行, 要读取所有行就必须创建一个循环来执行getline直到不再有输出为止。while("who" | getline)...注意:其中who命令值执行一次,但是getline则调用多次。

     close()函数: 关闭打开的文件或管道。

    因为:1. 每次只能代开一定数量的管道。 通常用在getline返回0或-1是,如close("who"). 2. 关闭管道使得你可以运行用一个命令两次。 3.为了得到一个输出管道来完成它的工作,使用close()可能是必要的,{some processing of $0 | "sort > tmpfile"}  END{close("sort > tmpfile")}

    system()函数执行命令。然而它没有产生可供程序处理的输出。它返回被执行命令的退出状态。 if(system("mkdir dale") != 0) print "failed!"

     直接向文件或管道输出:

    print和printf可以用输出重定向操作">"和">>"将结果直接写入到文件中。  print > data.out 将记录写入data.out

    print | command 直接暑促到管道。该命令在第一次执行时打开一个管道,并将当前记录作为输入传送给命令,换句话说这里的命令只执行一次,但每执行一次print将提供另一个输入行。

  • 相关阅读:
    论语学习系列(一)
    如何编译生成 dll
    Lua学习系列(二)
    Lua学习系列(一)
    Promise对象
    ... 扩展运算符
    class类
    proxy [ˈprɒksi] 代理
    HBuilder 打包流程
    Generator [ˈdʒenəreɪtə(r)] 函数结构
  • 原文地址:https://www.cnblogs.com/fly-xiang-zhao/p/4074287.html
Copyright © 2011-2022 走看看