《Linux命令行與shell腳本編程大全》初識sed和gawk
文本處理
sed編輯器
sed編輯器可以基於輸入到命令行的或是存儲在命令文本文件中的命令來處理數據流中的數據。
它每次讀取一行,用提供的編輯器命令匹配數據、按命令中指定的方式修改流中的數據,然後將生成的數據輸出到STDOUT。在流編輯器將所有命令與一行數據進行匹配後,它會讀取下一行數據並重復這個過程。在流編輯器處理完流中的所有數據行後,它就會終止。
sed命令格式:
sed options script file
sed命令選項
選項 描述
-e script 在處理輸入時,將script中指定的命令添加到運行的命令中
-f file 在處理輸入時,將file中指定的命令添加到運行的命令中
-n 不要為每個命令生成輸出,等待print命令來輸出
在命令行定義編輯器命令
默認情況下,sed會編輯器會將指定的命令應用到STDIN輸入流上。
[plain]
$ echo "This is a test" | sed 's/a/not a/'
This is not a test
在命令行使用多個編輯器命令
使用-e即可。
注意:多個命令都寫在同一對引號之間,並用分號隔開。並且在命令末尾和分號之間不能有空格。
[plain]
$ echo "This is a test" | sed -e 's/a/not a/;s/This/That/'
That is not a test
從文件中讀取編輯器命令
[plain]
$ cat sed_script
s/brown/white/
s/fox/elephant/
使用-f選項即可。
[plain]
$ echo "The quick brown fox jumps over the lazy dog." | sed -f sed_script
The quick white elephant jumps over the lazy dog.
文件中的sed命令可以使用換行或分號隔開
gawk程序
在gawk編程語言中,可以做下面的事:
1.定義變量來保存數據
2.使用算數和字符串操作符來處理數據
3.使用結構化編程概念,比如if-then語句和循環
4.提取數據文件中的數據元素並將他們按另一順序或格式重新放置。
gawk命令格式:
gawk option program file
gawk選項
選項 描述
-F fs 指定行中分隔數據字段的字段分隔符
-f file 指定讀取程序的文件名
-v var=value 定義gawk程序中的一個變量以及默認值
-mf N 指定要處理的數據文件中的最大字段數
-mr N 指定數據文件中的最大數據行數
-W keyword 指定gawk的兼容模式或警告等級
從命令行讀取程序腳本
gawk程序用一對花括號來定義。
由於gawk命令行假定腳本是單個文本字符串,所以必須將腳本放到單引號中。
[plain]
$ gawk '{print "Hello"}'
鍵入回車之後,並不會馬上執行,等待你輸入文本。gawk會對這行文本運行一遍所有的程序腳本
和sed一樣,gawk程序會針對數據流中的每行文本執行一遍程序腳本。
使用數據字段變量
gawk會將如下變量分配給它在文本行中發現的每個數據字段:
$0表示整個文本行;$1表示文本行中第一個數據字段,依此類推
gawk中默認的字段分隔符是任意空白字符
[plain]
$ echo "A B C
> D E F" | gawk '{print $1}'
A
D
使用-F選項指定分隔符
[plain]
$ gawk -F : '{print $1}' /etc/passwd
root
daemon
bin
sys
……
在程序腳本中使用多個命令
同sed,多個命令使用分號隔開即可。
[plain]
$ echo "I'm a person." | gawk '{$3="man.";print $0}'
I'm a man.
這裡先將$3賦值,然後打印這句話。打印得結果是已經替換了$3之後的結果了。
從文件中讀取程序
[plain]
$ cat gawk_test
{
text="'s home directory is "
print $1 text $6
}
同樣可以使用多個命令,可以用換行或分號分割命令
[plain]
$ gawk -F: -f gawk_test /etc/passwd
root's home directory is /root
daemon's home directory is /usr/sbin
……
gawk在引用變量得時候,並不像shell那樣,需要使用美元符
在處理數據前運行腳本
BEGIN關鍵字會在處理數據前,執行指定的腳本
[plain]
$ gawk 'BEGIN { print "hello world"}'
hello world
在處理數據後運行腳本
當然是使用END關鍵字了
[plain]
$ cat gawk_test
BEGIN {
print "Before read the file"
FS=":"
}
{
print $1
}
END {
print "The End"
}
注意:使用FS設置分割符
[plain]
$ gawk -f gawk_test /etc/passwd
Before read the file
root
daemon
……
sshd
Debian-exim
The End
sed編輯器基礎
更多的替換選項
替換標記
默認情況下,對匹配到的內容只會替換一次
[plain]
$ echo "That is a test." | sed 's/ //'
Thatis a test.
如果想改變這種方式,需要使用替換標記
s/pattern/replacement/flags
有4種替換標記:
數字,表明將替換第幾處模式匹配的地方
[plain]
$ echo "That is a test." | sed 's/ //2'
That isa test.
$ echo "That is a test." | sed 's/ //6'
That is a test.
g,替換所有匹配到的文本
[plain]
$ echo "That is a test." | sed 's/ //g'
Thatisatest.
p,表明原來行的地方要打印出來。通常與-n選項一起使用
上面已經說過,-n選項表示不輸出,等待print命令來輸出。
[plain]
$ echo "That is a test." | sed -n 's/ //p'
Thatis a test.
w file,將替換的結果寫到文件中
[plain]
$ echo "That is a test." | sed -n 's/ //w out'
$ cat out
Thatis a test.
替換字符
如果我們想要替換文本中出現的文件路徑,那麼就需要轉義符
[plain]
$ pwd | sed 's/\/home/\/myhome/'
/myhome/su1216/android/source/linux_learned
或者,我們也可以把命令中的字符串分割符“/”給替換掉
[plain]
$ pwd | sed 's@home@myhome@'
/myhome/suzhaoqiang/android/source/linux_learned
使用地址
默認情況下,sed會對所有行使用命令,如果只想將命令作用於特定某些行,需要使用行尋址(line addressing)
sed中有兩種形式的行尋址:
1.行的數字范圍
2.用文本模式來過濾出某行
兩種形式都使用相同的格式來指定地址:
[address] command
也可以為特定地址將多個命令放在一起:
address {
command1
command2
command3
}
數字方式的行尋址
[plain]
$ cat test.txt
This is a test.
This is a test.
This is a test.
This is a test.
This is a test.
This is a test.
This is a test.
$ sed '3,$s/This/That/' test.txt
This is a test.
This is a test.
That is a test.
That is a test.
That is a test.
That is a test.
That is a test.
從第三行開始,到最後一行(最後一行用美元符號表示)進行替換
使用文本模式過濾器
格式如下:
/pattern/command
該命令只會作用到匹配文本模式的行上。sed在文本模式中采用正則表達式。
[plain]
sed '/su1216/s!home!myhome!' /etc/passwd
root:x:0:0:root:/root:/bin/bash
……
su1216:x:1000:1000:su1216,,,:/myhome/su1216:/bin/bash
……
組合命令
需要對單行執行多條命令的話,可以使用花括號將多條命令組合在一起
[plain]
$ sed '2{
s/This/That/
s/test/good test/
}' test.txt
This is a test.
That is a good test.
This is a test.
This is a test.
刪除行(delete)
刪除行的命令為d,如果不指定行號,那麼就全部刪除。
[plain]
$ sed '2,4d' test.txt
line 1
line 5
line 6
sed編輯器的模式匹配也適用於刪除命令:
[plain]
$ sed '/line 3/d' test.txt
line 1
line 2
line 4
line 5
line 6
注意:sed不會修改原始文件。
可以用兩個文本模式來刪除某個范圍內得行。
指定的第一個文本模式會打開行刪除功能,第二個會關閉行刪除功能。如果沒有匹配到第二個,那麼後面的文本將全部刪除。
如果匹配到了第二個,那麼sed還會繼續嘗試匹配第一個,繼續嘗試再次打開刪除功能!
[plain]
$ sed '/line 2/,/line 4/d' test.txt
line 1
line 5
line 6
插入和附加文本
插入(insert)命令i會在指定行前加一個新行
追加(append)命令a會在指定行後加一個新行
格式如下:
sed '[address]command\
new line'
[plain]
$ echo "Line" | sed 'i\Line 1'
Line 1
Line
$ echo "Line" | sed 'a\Line 1'
Line
Line 1
在數據流的最後添加新行
[plain]
$ sed '$a\new line' test.txt
line 1
line 2
line 3
line 4
line 5
line 6
new line
修改行(change)
和之前的使用完全一樣
使用地址區間的時候需要注意,sed會把區間中的所有內容作為一個整體用新行替換
[plain]
$ sed '2,4c\new line' test.txt
line 1
new line
line 5
line 6
轉換命令
轉換(transform,y)命令是唯一可用處理單個字符的sed編輯器命令
格式如下:
[addressly/inchars/outchars/
轉換命令會對inchars和outchars按順序做一個一一映射。
如果inchars和outchars長度不同,sed則會產生錯誤信息
[plain]
$ sed 'y/123/abc/' test.txt
A:aabbaacc
B:44aa55bb
轉換命令是全局的,他們將所有指定的字符都替換成目標字符。
回顧打印
用來打印數據流中的信息的命令:
1.p,用來打印文本行
2.等號(=)命令,用來打印行號
3.l(小寫L)命令,用來列出行
打印行
和替換命令中的p標記類似,p命令可以打印sed編輯器輸出中的一行
[plain]
$ echo "hello" | sed 'p'
hello
hello
$ echo "hello" | sed -n 'p'
hello
也可以使用文本模式
[plain]
$ cat test.txt
A:11221133
B:44115522
line 3
line 4
line 5
$ sed -n '/line/p' test.txt
line 3
line 4
line 5
可以與替換命令一起使用,下面是修改一行,並且打印出修改前的這一行
[plain]
$ sed -n '/3/{p;s/line/Line/p}' test.txt
A:11221133
line 3
Line 3
含有3的有兩行,其中後面一行滿足條件,然後被替換。
打印行號
[plain]
$ sed '=' test.txt
1
A:11221133
2
B:44115522
3
line 3
4
line 4
5
line 5
行號由換行符決定。
[plain]
$ sed -n '/line/{=;p}' test.txt
3
line 3
4
line 4
5
line 5
列出行
此命令允許打印數據流中的文本和不可打印的ASCII字符。
任何不可打印字符都用他們的八進制值前加一個反斜線或標准C風格的命名法。
[plain]
$ sed -n 'l' test.txt
A:11221133$
B:44115522$
line 3$
line 4$
line 5$
比如制表符用\t表示,行結束用$表示。
用sed和文件一起工作
向文件寫入
格式如下:
[address]w filename
[plain]
$ sed '1,2w sed_w_test' test.txt
A:11221133
B:44115522
line 3
line 4
line 5
$ cat sed_w_test
A:11221133
B:44115522
當然,我們可以改成下面的形式
[plain]
$ sed -n '1,2w sed_w_test' test.txt
$ cat sed_w_test
A:11221133
B:44115522
從文件讀取數據
格式如下:
[address]r filename
讀取命令允許將一個獨立文件中的數據插入到數據流中。
[plain]
$ cat sed_w_test
A:11221133
B:44115522
$ sed '4r sed_w_test' test.txt
A:11221133
B:44115522
line 3
line 4
A:11221133
B:44115522
line 5
如果想插到文件末尾,可以使用$