shell sed命令詳解:選取、替換、刪除、新増資料

2020-07-16 10:04:34
sed 是一種幾乎可以應用在所有 UNIX 平台(包括 Linux)上的輕量級流編輯器。sed 有許多很好的特性。首先,它相當小巧,通常要比你所喜愛的指令碼語言小多倍。其次,因為 sed 是一種流編輯器,所以,它可以對從如管道這樣的標準輸入中接收的資料進行編輯。因此,無須將要編輯的資料儲存在磁碟上的檔案中。因為可以輕易將資料管道輸出到 sed,所以,將 sed 用作強大的 Shell 指令碼中長而複雜的管道很容易。

sed 主要是用來將資料進行選取、替換、刪除、新増的命令。我們看看命令的語法:

[[email protected] ~] # sed [選項] '[動作]' 檔名

選項:
  • -n:一般 sed 命令會把所有資料都輸出到螢幕上。如果加入此選項,則只會把經過 sed 命令處理的行輸出到螢幕上;
  • -e: 允許對輸入資料應用多條 sed 命令編輯;
  • -f 指令碼檔名:從 sed 指令碼中讀入 sed 操作。和 awk 命令的 -f 選項非常類似;
  • -r:在 sed 中支援擴充套件正規表示式;
  • -i:用 sed 的修改結果直接修改讀取資料的檔案,而不是由螢幕輸出動作;
  • a :追加,在當前行後新增一行或多行。當新增多行時,除最後一行外,每行末尾需要用“”代表資料未完結;
  • c :行替換,用c後面的字串替換原資料行。當替換多行時,除最後一行外,每行末尾需用“”代表資料未完結;
  • i :插入,在當前行前插入一行或多行。當插入多行時,除最後一行外,每行末尾需要用“”代表資料未完結;
  • d:刪除,刪除指定的行;
  • P:列印,輸出指定的行;
  • s:字串替換,用一個字串替換另一個字串。格式為“行範圍s/舊字串/新字串/g”(和Vim中的替換格式類似);

大家需要注意,sed 所做的修改並不會直接改變檔案的內容(如果是用管道符接收的命令的輸出,則連檔案都沒有),而是把修改結果只顯示到螢幕上,除非使用"-i"選項才會直接修改檔案。

行資料操作

舉幾個例子來看看 sed 命令到底是幹什麼的。假設我想檢視一下 student.txt 檔案的第二行,就可以利用"p"動作了。

[[email protected] ~]# sed '2p' student.txt
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66

好像看著不怎麼順眼啊!"p"動作確實輸出了第二行資料,但是 sed 命令還會把所有資料都輸出一次,這時就會看到這個比較奇怪的結果。那如果我想指定輸出某行資料,就需要"-n"選項的幫助了。

[[email protected] ~]# sed -n '2p' student.txt
1 Liming 82 95 86 87.66

這樣才可以輸出指定的行。大家可以這樣記憶:當我們需要輸出指定的行時,需要把"-n"選項和"p"動作一起使用。

再來看看如何刪除檔案中的資料:

[[email protected] ~]#sed '2,4d' student.txt
#刪除從第二行到第四行的資料
ID Name PHP Linux MySQL Average
[[email protected] ~]# cat student.txt
#檔案本身並沒有被修改
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66


看到這條命令首先需要注意,所有的動作必須使用"單引號"包含;其次,在動作中可以使用數位代表行號,逗號代表連續的行範圍。還可以使用"$"代表最後一行,如果動作是"2,$d",則代表從第二行刪除到最後一行。

再來看看如何追加和插入行資料:

[[email protected] ~]# sed '2a hello' student.txt
#在第二行後加入hello
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
hello
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66

"a"動作會在指定行後追加資料。如果想要在指定行前插入資料,則需要使用"i"動作。

[[email protected] ~]# sed '2i hello > world' student.txt
#在第二行前插入兩行資料
ID Name PHP Linux MySQL Average
hello
world
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66

如果想追加或插入多行資料,則除最後一行外,每行的末尾都要加入""代表資料未完結。

再來看看"-n"選項的作用,命令如下:

[[email protected] ~]# sed -n'2i hello
#只檢視sed命令操作的麵
world' student.txt
hello
world

看到了吧,"-n"只用於檢視 sed 命令操作的資料,而並非檢視所有的資料。

再來看看如何實現行資料替換:

[[email protected] ~]# cat student.txt | sed '2c No such person'
ID Name PHP Linux MySQL Average
No such person
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66


第二行資料變成了 "查無此人"。通過這個例子我們看到了,sed 也可以接收和處理管道符傳輸的資料。

sed 命令在預設情況是不會修改檔案內容的。如果我確定需要讓 sed 命令直接處理檔案的內容,則可以使用"-i"選項。不過要小心,這樣非常容易誤操作,在作業系統檔案時請小心謹慎。可以使用這樣的命令:

[[email protected] ~]# sed -i'2c No such person' student.txt

字串替換

"c"動作是進行整行替換的,如果僅僅想替換行中的部分資料,就要使用"s"動作了。"s"動作的格式如下:

[[email protected] ~]# sed's/舊字串/新字串/g' 檔名

替換的格式和 Vim 非常類似,例如:

[[email protected] ~]# sed '3s/74/99/g' student.txt
#在第三行中,把74換成99
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 99 96 87 85.66
3 Gao 99 83 93 91.66


如果想把某行的成績註釋掉,讓它不再生效,則可以這樣做:

[[email protected] ~]#sed '4s/^/#/g' student.txt
#在這裡使用正規表示式,"^"代表行首
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
#3 Gao 99 83 93 91.66


不僅如此,我們還可以這樣做:

[[email protected] ~]# sed -e 's/Liming//g; s/Gao//g' student.txt
#同時把"Liming"和"Gao"替換為空
ID Name PHP Linux MySQL Average
1 82 95 86 87.66
2 Sc 74 96 87 85.66
3 99 83 93 91.66


"-e"選項可以同時執行多個 sed 動作,當然,如果只執行一個動作,則也可以使用"-e"選項,但是這時沒有什麼意義。還要注意,多個動作之間要用";"或回車分隔,例如,上一條命令也可以這樣寫:

[[email protected] ~]# sed -e 's/Liming//g
> s/Gao//g' student.txt
ID Name PHP Linux MySQL Average
1 82 95 86 87.66
2 Sc 74 96 87 85.66
3 99 83 93 91.66