Sed Awk Notes

Introduction to Sed & Awk and Reguluar Expression

Regular Expression

一個Regular Expression是用來描述某種型式的字串(string)。以下以RE稱之:

Regular Expression 中的特殊符號

  • . 可以用來代表任一字元(除了換行以外)
  • * 它之前的字元可以出現0次或是多次,而且會儘量對應到最長可能的範圍

o [15]00* 表示1 or 5開頭,後面接至少一個0

  • ^ 如果出現在Regular Expression中的開頭就代表輸入資料的開頭,在[]開頭中則代表not
  • $ 如果出現在Regular Expression中的結尾就代表輸入資料的結尾
    • ^$ 可表示空行
  • \{n,m\}指出現的次數在n~m次之間
    • 10\{2,4\}1 可對應1接著2~4個0在接著1
  • \使下一個出現符號失去特殊意義
  • […] 在括號內之所有字元所成之集合,有符合其中之一字元
    • 當]出現在[]中的第一個字元時,它只代表一般字元
    • [^0-9] 會對應到任一非數字之字元
    • [A-Za-z] 表示所有英文字母
  • () 可聚集一群RE
    • compan(y|ies) 表示company 或 companies

Regular Expression 中的衍伸特殊符號

  • + 它之前的RE可以出現1次或是多次
  • ? 它之前的RE可以出現0次或是多次
  • | 它之前的RE或之後之RE代表之字串 (or)

Sed

命令通式
[address[,address]][!] command [arguments] [line-address] : 資料列只能是一行
[address] : 資料列可以是某一範圍

參數

-n : 只印出命令p所印出的資料列,或帶有標幟之命令s
-e cmd : 表示下一個引數是編輯命令
-f file : 表示下一個引數是包含編輯命令的檔案

Substitution:

[address]s/pattern/replacement/flags
flag:
n: (1~512)代表在第n次出現該pattern時,才進行取代
g: 不指定此flag,只會取代第一次出現之pattern
p: 印出
Ex:
s/UNIX/xxx&xxx/g (會把UNIX變成xxxUNIXxxx,也就是&符號代表整個pattern對應結果)
s/\(Section\) \([0-9][0-9]*\)\.\([0-9][0-9]*\)/\2\3/ (會把Section x.c變成xc)

Delete:

Ex:
/^$/d (刪掉空行)
/^haha/d (刪掉開頭是haha的)

Append & Insert & Change:

append:
[line-address]a text
insert:
[line-address]i text
change:
[address]c text

Ex:
/pattern/i hello every one
(會在pattern前面加上兩行)
/^From /,/^$/c mail Header Removed
(會把整個郵件的標頭改成mail Header Removed)
/^From /,/^$/{
s/^From //p
c mail Header Removed
}
(會把整個郵件的標頭的每一行改成mail Header Removed)
/^Section/c Section 1\.1
(會把開頭是Section的行變成Section 1.1,而不管原本是第幾節)

List

Ex:
sed -n -e "l" file(可以把看不到字元印出)

Transform

[address]y/abc/xyz/
把a轉成x, 把b轉成y, 把c轉成z
Ex:
y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ (小寫轉大寫)

Next line(n)

[address]n
Ex:
/hell/{
n
/^$/d
}
(會刪除有hell的下一列空行)
* 印出是第幾列

[line-address]=
Ex:
/hello/{
=
}
(會印出hello的是那幾列)

Quit

[line-address]q
Ex:

          /begin/,/end/
          {
              p
              /^end/q
          }
          (當找到end時就停下來)

附加下一行(N)

Ex:

           s/hello world/Hello World/
            /hello/ {
            N
            s/ *\n */ /
            s/hello world */Hello World\
            /
            }

(把下一列附加進來,當hello world不是在同一列時,可以進行取代)

多列刪除(D)

每次只刪到第一個\n,它執行完後會回到開頭重新執行.
Ex:
/^$/{
N
/^\n$/d
}
(當空行數是偶數時,會把多個空行變成一個,是奇數時則全部都刪掉)
/^$/{
N
/^\n$/D
}
(會把多個空行變成一個,因為當有兩個空行它只會刪掉第一個,然後停留在第二行)

多列印出(P)

只印出至第一個newline
Ex:

              /UNIX$/ {
                  N
                  /\nSystem/ {
                  s// Operating &/
                  P
                  D
                  }
              }

(當輸入是UNIX\nSystem UNIX\n System時,當處理第一次時,P只先印出UNIX Operanting\nSystem,
但還是停在第二行的UNIX上,所以可以處理同一行的UNIX)

保留空間

h : 將樣式空間的內容複製到保留空間
H : 將樣式空間的內容append到保留空間
g : 將保留空間的內容複製到樣式空間
G : 將保留空間的內容append到樣式空間
樣式空間就是buffer,內含現在處理到的那一列
保留空間(hold space)是輔助緩衝區
Ex:

1.

          /the .* statement/{
              h
              s/.*the \(.*\) statement.*/\1/
              y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
              G
              s/\(.*\)\n\(.*the \).*\( statement.*\)/\2\1\3/
          }

(是把the xxx statement中的xxx變成大寫,先把整句放入hold space,然後只留中間的部分,在轉大寫,在把之前那在hold space中完整句抓出來,按照順序擺好)

2.

          $
          {
          /^$/!{
              H
              s/.*//
              }
          }
          /^$/! {
              H
              d
          }
          /^$/ {
              x
              s/^\n/< p>/
              s/$/<\/p>/
              G
          }

(會在段落前後加< p>的tag,如果遇到不是空行的就放進hold space,等到遇到空行時,就進行取代,並把空行放在最後,如果最後一行不是空行,就把它變成空行)

分支指令

[address]b[label]
label可有可無,若沒指令則執行流程會轉到結尾
Ex:

1.
:top
command1
command2
/pattern/b top
command3
(當pattern不相符時,command3才會執行)
2.
command1
/pattern/b end
command2
:end
command3
(command2可能會被跳過)
3.
command1
/pattern/b dothree
b
:dothree
command3
(所比對成功會跳到dothree,反之結束)

測試指令

[address]t[label]
只有當在它之前的替換指令成功的作用於當前資料時,才會將執行流程轉移到label,而label可有可無,若沒指令則執行流程會轉到結尾
Ex:

1.

          /pattern/{
              s/"\(.*\)" "\(.*\)" "\(.*\)"/"\1" "\2" "\3"/
              t break
              s/"\(.*\)" "\(.*\)"/"\1" "\2"/
              t break
              s/"\(.*\)"/"\1"/
          }
          :break
              more commands

(會根據參數的數目來決定)
2.

          :begin
          /@begin(\([^]*\))/{
              s//\\begin\1\\end/g
              b begin
          }
          /@begin(.*/{
              N
              s/@begin(\([^)]*\))/\\begin\1\\end/g
              t again
              b begin
          }
          :again
          P
          D

(可以跨很多列的@begin(….),第一部分是當在同一列時,第2部分就是在不同列,經由判斷,如果沒有替換成功,
就跳回begin繼續判斷)

Awk

流程 BEGIN —> statements --> END

BEGIN : 在程式讀進任何資料之前
statement : 任何其它指令 END : 所有資料讀完後,要結束之前

系統變數

  • FS : 定義欄位符號的變數(預設是空白)
  • OFS : 定義輸出欄位符號的變數(預設是空白,就是在print中分隔的',')
  • NF : 當前輸入紀錄中欄位的數目
  • RS : 紀錄區隔符號(預設是換行,就是區別每筆紀錄的符號)
  • ORS : 輸出紀錄區隔符號(預設是換行)
  • FILENAME : 目前輸入檔案名稱
  • CONVFMT : 由數字到字串之轉換(預設是%.6g)
  • NR : 代表已讀過之紀錄總數
  • ARGC : 命令列引數的個數
  • ARGV : 命令列引數所存之陣列
  • OFMT : 數字的輸出編排方式
  • RLENGTH : match()所找到之子字串的長度
  • RSTART : match()所找到之子字串位於原本字串的開頭位置
  • SUBSET : 陣列下標值的區隔符號(多維陣列index的區隔)
  • ENVIRON : 用來存環境變數之陣列

Ex:

      1.
          {
              total = $2 + $3
                  print NR ".", $1,total/2
          }
          (把兩欄分數平均)
      2.
          NR == 1
          {
              print "Begining Balance: " $1
              balance = $1
          }
      # 自存款中減去花費
          {
              print $1,$2,$3
              print balance -= $3
          }
          (一開始是存款,接著就是日期,何處消費,花費)
      3.
          $5 ~ /MA/ { print $1,$6 }
          (第五欄位是否跟MA匹配)

printf

printf( format-expression [ , arguments ] )
o e/E : 科學(指數)表示法
o g : 轉成 e 或 f 取最短者,並去掉尾部的0
o G : 轉成 E 或 f 取最短者,並去掉尾部的0
o (其它跟 C 的printf格式一樣)
o %-width.precision
Ex:

1.
printf("%*.*d\n",5,3,val);

判斷敘述

      if ( expression )
          action1
      [[else if action3] else action2]

      expr ? action1 : action2

      Ex:

      1.
          grade = (avg >=65) ? "Pass" : "Fail"
      2.
          if(a==5)
              print a
          else if(a==6)
              print a+1
          else print a+2

迴圈敘述

      while (condition)
          action

      do
          action
      while(condition)

      for( set_counter;test_counter;increment_counter)
          action
      set_counter:設定初值
      test_counter:測試條件
      increment_counter:增加變數值

Ex:

      1.
          i=1
          while(i < 4)
          {
              print $i
              i++
          }
      2.
          do {
              x++
              print x,$x    # 印出第x個參數
          } while(x < 4)
      3.
          for(i=1;i < 4;i++)
          {
              if(i==3)
                  continue
              print $x
          }

階乘範例

陣列

o 陣列:
o 關聯式陣列:
對於關聯式陣列,有一種for型式,而數字會根據OFMT or CONFMT的值被轉換成字串

for( variable in array )
do something with array[variable]

item in array : 判斷此item是否在關聯式陣列array中 delete array[subscript] : 刪除陣列中的元素 n = split(string,array,separator) : 依據separator來把string分割到array中,回傳n代表總元素個數多維陣列: array[a , b , c …] 在多維陣列中:

for (item in array)
split(item,subscr,SUBSEP) #必需以SUBSEP取出分開的下標

awk內建有兩個環境變數的陣列,ARGV and ENVIRON

      BEGIN {
          for(x=0;x < ARGC;x++)
              print ARGV[x]
          print ARGC
      }

      BEGIN {
          for (env in ENVIRON)
              print env "=" ENVIRON[env]
      }

函式

      function name (parameter-list)
      {
          statement
          [ return expression ]
      }

      sort function

Build-in function getline Ex1

Ex2

      awk '#getname from /etc/passwd
      BEGIN {
          "whoami" | getline
          name = $1
          FS = ":"
      }
      name ~ $1 { print $5 }
      ' /etc/passwd
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License