《linux命令列與shell指令碼程式設計大全》第三版 - 核心筆記(3/4):sed和gawk

不才b_d發表於2017-07-02
《linux命令列與shell指令碼程式設計大全》
全書4部分:
☆ 【1】linux命令列(1-10章)
☆ 【2】shell指令碼程式設計基礎(11-16章)
☆ 【3】高階shell指令碼程式設計(17-23章):sed編輯器和gawk程式
☆ 【4】建立實用的指令碼(24-26章)


>>第19章丶sed編輯器和gawk程式

sed編輯器
流編輯器,和普通的互動式文字編輯器恰好相反。sed編輯器會執行以下操作:
(1) 一次從輸入中讀取一行資料。
(2) 根據所提供的編輯器命令匹配資料。
(3) 按照命令修改流中的資料。
(4) 將新的資料輸出到STDOUT。


sed命令的格式如下。
    sed options script file
sed命令選項:
-e script 在處理輸入時,將script中指定的命令新增到已有的命令中
-f file 在處理輸入時,將file中指定的命令新增到已有的命令中
-n 不產生命令輸出,使用print命令來完成輸出
預設情況下, sed編輯器會將指定的命令應用到STDIN輸入流上。這樣你可以直接將資料通過管道輸入sed編輯器處理。

$: echo "This is a test." | sed 's/test/big test/'
This is a big test.

$: cat data1.txt
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
$: sed 's/dog/cat/' data1.txt
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.

sed編輯器並不會修改文字檔案的資料。它只會將修改後的資料傳送到STDOUT。

-e選項

在命令列使用多個編輯器命令。
$: sed -e '
>s/brown/green/
>s/fox/elephant/
>s/dog/cat/' data1.txt

The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
// 要在封尾單引號所在行結束命令。 bash shell一旦發現了封尾的單引號,就會執行命令。s命令的結尾符號/必須要有,否則報錯。

-f選項

從檔案中讀取編輯器命令。
$: cat script1.sed
s/brown/green/
s/fox/elephant/
s/dog/cat/
$: sed -f script1.sed data1.txt
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.

[竅門]我們很容易就會把sed編輯器指令碼檔案與bash shell指令碼檔案搞混。為了避免這種情況,可以使用.sed作為sed指令碼檔案的副檔名。

gawk程式

提供一個類程式設計環境來修改和重新組織檔案中的資料。
$: sudo apt-get install gawk
$: gawk -W version
GNU Awk 3.1.8
版權所有 © 1989, 1991-2010 自由軟體基金會(FSF)。

gawk程式會執行以下操作:
 定義變數來儲存資料;
 使用算術和字串操作符來處理資料;
 使用結構化程式設計概念(比如if-then語句和迴圈)來為資料處理增加處理邏輯;
 通過提取資料檔案中的資料元素,將其重新排列或格式化,生成格式化報告。

gawk程式的報告生成能力通常用來從大文字檔案中提取資料元素,並將它們格式化成可讀的報告。其中最完美的例子是【格式化日誌檔案】。

gawk程式的基本格式如下:
    gawk options program file

gawk程式選項:
-F fs           指定行中劃分資料欄位的欄位分隔符,如-F:即以冒號來劃分
-f file         從指定的檔案中讀取程式
-v var=value    定義gawk程式中的一個變數及其預設值
-mf N           指定要處理的資料檔案中的最大欄位數
-mr N           指定資料檔案中的最大資料行數
-W keyword      指定gawk的相容模式或警告等級

從命令列讀取程式指令碼:
Ctrl+D組合鍵會在bash中產生一個EOF字元。
$: gawk '{printf "Hello World!"}'
This is a test.
Hello World!
Hello World!hello
Hello World!
Hello World!^D
// Ctrl+D組合鍵會在bash中產生一個EOF字元。能夠終止gawk程式並返回到命令列。

使用資料欄位變數:
預設情況下, gawk會將如下變數分配給它在文字行中發現的資料欄位:
 $0代表整個文字行;
 $1代表文字行中的第1個資料欄位;
 $2代表文字行中的第2個資料欄位;
 $n代表文字行中的第n個資料欄位。

每個資料欄位都是通過欄位分隔符劃分的。gawk中預設的欄位分隔符是任意的空白字元(例如空格或製表符)。
$: cat data2.txt
One line of test text.
Two lines of test text.
Three lines of test text.
$: gawk '{print $2}' data2.txt
line
lines
lines

-F:
$: gawk -F: '{print $1}' /etc/passwd
root
bin
daemon
adm
lp
...

$: echo "My name is Rich" | gawk '{$4="Christine"; print $0}'
My name is Christine

$: cat script2.gawk
{print $1 "'s home directory is " $6}
$: gawk -F: -f script2.gawk /etc/passwd
root's home directory is /root
bin's home directory is /bin
daemon's home directory is /sbin
adm's home directory is /var/adm
lp's home directory is /var/spool/lpd
[...]

有時可能需要在處理資料前執行指令碼,比如為報告建立標題。BEGIN關鍵字就是用來做這個的。它會強制gawk在讀取資料前執行BEGIN關鍵字後指定的程式指令碼。
END關鍵字允許你指定一個程式指令碼, gawk會在讀完資料後執行它。這是在處理完所有正常資料後給報告新增頁尾的最佳方法。
$: gawk 'BEGIN {print "The data3 File Contents:"}
> {print $0}
> END {print "End of File"}' data3.txt

The data3 File Contents:
Line 1
Line 2
Line 3
End of File

$: cat script4.gawk
BEGIN {
    print "The latest list of users and shells"
    print " UserID \t Shell"
    print "-------- \t -------"
    FS=":"
}
{
    print $1 " \t " $7
}
END {
    print "This concludes the listing"
}


$: gawk -f script4.gawk /etc/passwd
The latest list of users and shells
UserID Shell
-------- -------
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
...
Christine /bin/bash
mysql /bin/bash
Samantha /bin/bash
Timothy /bin/bash
This concludes the listing

sed編輯器標記命令

s替換標記

要讓替換命令能夠替換一行中不同地方出現的文字必須使用替換標記(substitution flag)。替換標記會在替換命令字串之後設定。
    s/pattern/replacement/flags
有4種可用的替換標記:
 數字,表明新文字將替換第幾處模式匹配的地方;
 g,表明新文字將會替換所有匹配的文字;
 p,表明原先行的內容要列印出來;
 w file,將替換的結果寫到檔案中。


$ sed 's/test/trial/2' data4.txt
// 將data4.txt檔案中的第二處出現test的地方替換為trial
$ sed 's/test/trial/g' data4.txt
// 將data4.txt中所有出現test的地方替換為trial
$ sed -n 's/test/trial/p' data5.txt
// -n與p一般配合使用,只輸出test被trial替換後,即修改過的行。
$ sed 's/test/trial/w test.txt' data5.txt
// 將data5.txt中的test替換為trial後,輸出到螢幕並儲存到檔案test.txt中

sed編輯器允許選擇其他字元來作為替換命令中的字串分隔符,而不必一定要使用轉義字元'\':
$ sed 's!/bin/bash!/bin/csh!' /etc/passwd

如果只想將命令作用於特定行或某些行,則必須用行定址(line addressing)。
在sed編輯器中有兩種形式的行定址:
 以數字形式表示行區間
 用文字模式來過濾出行

兩種形式都使用相同的格式來指定地址:
    [address]command
也可以將特定地址的多個命令分組:
address {
    command1
    command2
    command3
}


$ sed '2s/dog/cat/' data1.txt
// 只修改地址指定的第二行的文字:2
$ sed '2,3s/dog/cat/' data1.txt
// 只修改地址指定的第二行和第三行的文字:2,3
$ sed '2,$s/dog/cat/' data1.txt
// 修改地址指定的第二行開始的所有行文字:2,$

也可以在多行實現,需要加{}:
$ sed '2{
> s/fox/elephant/
> s/dog/cat/
> }' data1.txt

The quick brown fox jumps over the lazy dog.
The quick brown elephant jumps over the lazy cat.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.

sed編輯器允許指定文字模式來過濾出命令要作用的行。格式如下:
    /pattern/command
必須用正斜線將要指定的pattern封起來。
$: grep jiangyuan /etc/passwd
jiangyuan:x:1001:1001:jiangyuan,,,:/home/jiangyuan:/bin/bash
$: sed '/jiangyuan/s/bash/csh/' /etc/passwd > passwd.bak && grep jiangyuan passwd.bak
jiangyuan:x:1001:1001:jiangyuan,,,:/home/jiangyuan:/bin/csh
// 過濾jiangyuan的行,sed過濾後的結果輸出到passwd.bak檔案,搜passwd.bak檔案中搜尋出包含jiangyuan的行。

d刪除行

sed編輯器不會修改原始檔案。你刪除的行只是從sed編輯器的輸出中消失了。原始檔案仍然包含那些“刪掉的”行。
$ sed '3d' data6.txt
// 在輸出流中刪除第三行
$ sed '2,3d' data6.txt
// 在輸出流中刪除第二、三行
$ sed '3,$d' data6.txt
// 在輸出流中刪除第三行開始的所有行
$ sed '/number 1/d' data6.txt
// 在輸出流中刪除匹配到了 number 1 的行

i前插行a後插行

sed編輯器允許向資料流插入和附加文字行。
 插入(insert)命令(i)會在指定行前增加一個新行;
 附加(append)命令(a)會在指定行後增加一個新行。

格式如下:
sed '[address]command\
new line'


$ echo "Test Line 2" | sed 'i\Test Line 1'
// 在行2前插入行1
$ echo "Test Line 2" | sed 'a\Test Line 1'
// 在行2後插入行1
$ echo "Test Line 2" | sed 'i\
> Test Line 1'

// 在行2前插入行1
$ sed '3i\
> This is an inserted line.' data6.txt

// 在檔案中的第3行前插入一行內容
$ sed '3a\
> This is an appended line.' data6.txt

// 在檔案中的第3行後插入一行內容
$ sed '$a\
> This is a new line of text.' data6.txt

// 在檔案中的最後一行後前插入一行內容
$ sed '1i\
> This is one line of new text.\
> This is another line of new text.' data6.txt

// 在檔案中的第1行前插入兩行內容

c修改行

 修改(change)命令(c)會把指定行修改為一個新行。
$ sed '3c\
> This is a changed line of text.' data6.txt

// 修改第三行的內容
$ sed '/number 3/c\
> This is a changed line of text.' data6.txt

// 修改匹配到number 3的行內容
$ sed '2,3c\
> This is a new line of text.' data6.txt

// 修改2和3行為一行內容

y轉換行

轉換(transform)命令(y)是唯一可以處理單個字元的sed編輯器命令。轉換命令格式如下:
    [address]y/inchars/outchars/
轉換命令會對inchars和outchars值進行一對一的對映。 inchars中的第一個字元會被轉換為outchars中的第一個字元,第二個字元會被轉換成outchars中的第二個字元。這個對映過程會一直持續到處理完指定字元。
$ sed 'y/123/789/' data8.txt
This is line number 7.
This is line number 8.
This is line number 9.
This is line number 4.
This is line number 7 again.
This is yet another line.
This is the last line in the file.

sed的列印

另外有3個命令也能用來列印資料流中的資訊:
 p命令用來列印文字行;
 等號(=)命令用來列印行號;
 l(小寫的L)命令用來列出行。


$ echo "this is a test" | sed 'p'
this is a test
this is a test
$ sed -n '/number 3/p' data6.txt
This is line number 3.
$ sed -n '2,3p' data6.txt
This is line number 2.
This is line number 3.
$ sed '=' data1.txt
1
The quick brown fox jumps over the lazy dog.
$ sed -n 'l' data9.txt
This\tline\tcontains\ttabs.

sed 處理檔案

寫入檔案,w命令用來向檔案寫入行。該命令的格式如下:
    [address]w filename
將資料流中的前兩行列印到一個文字檔案中。
$ sed '1,2w test.txt' data6.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
$ cat test.txt
This is line number 1.
This is line number 2.
// 如果你不想讓行顯示到STDOUT上,你可以用sed命令的-n選項。

從檔案讀取資料,讀取(read)命令(r)允許你將一個獨立檔案中的資料插入到資料流中。讀取命令的格式如下:
    [address]r filename

$ cat data12.txt
This is an added line.
This is the second added line.
$ sed '3r data12.txt' data6.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is an added line.
This is the second added line.
This is line number 4.






2017.07.02
第19章完... (全書未完待續!)

相關文章