shell基礎 -- grep、sed、awk命令簡介

来源:https://www.cnblogs.com/tongye/archive/2018/10/09/9747560.html
-Advertisement-
Play Games

在 shell 編程中,常需要處理文本,這裡介紹幾個文本處理命令。 一、grep 命令 grep 命令由來已久,用 grep 命令來查找 文本十分方便。在 POSIX 系統上,grep 可以在兩種正則表達式風格中選擇一種(BRE 和 ERE),或是執行簡單的字元串匹配。傳統上,有三種程式可以用來查找 ...


  在 shell 編程中,常需要處理文本,這裡介紹幾個文本處理命令。

一、grep 命令

grep 命令由來已久,用 grep 命令來查找 文本十分方便。在 POSIX 系統上,grep 可以在兩種正則表達式風格中選擇一種(BRE 和 ERE),或是執行簡單的字元串匹配。傳統上,有三種程式可以用來查找整個文本文件:

1)grep:最早的文本匹配程式。使用 POSIX 標准定義的基本正則表達(Basic Regular Expression,BRE);

2)egrep:擴展 grep。使用擴展正則表達式(Extended Regular Expression,ERE);

3)fgrep:快速 grep。匹配固定字元串而非正則表達式,它使用優化的演算法,能更有效地匹配固定字元串。

  在目前的 POSIX 標準中,這三個程式已經被整合成為一個程式 grep,通過對 grep 命令加以不同的選項進行選擇控制。

  grep 命令由一個選項、一個要匹配的模式和要搜索的文件組成,語法如下: 

grep [options] PATTERN [FILES]

  如果沒有提供文件名,則 grep 命令將搜索標準輸入。grep 命令將會根據所提供的模式對文件進行匹配,發現匹配查找模式的行時,將該行顯示出來。當 grep 命令同時搜索多個文件時,將會在搜索結果每一行前面加上文件名與一個冒號。grep 命令的主要選項如下:

選項 功能
-E 使用擴展正則表達式進行匹配(取代傳統的 egrep 命令)
-F 使用固定字元串進行匹配(取代傳統的 fgrep 命令)
-c   輸出匹配行的數目,而不是輸出匹配的行
-h 取消每個輸出行的普通首碼,即匹配查詢模式的文件名
-i 忽略大小寫
-l 只列出包含匹配行的文件名,而不輸出真正的匹配行
-v 對匹配模式取反,即搜索匹配不到的行
-n 輸出行號

   用例子演示一下:

[tongye@localhost ~]$ grep -ni ROOT /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin

  該命令將會在 /etc/passwd 中查找有 root 的行,並將該行顯示出來, -n 選項輸出行號,-i 選項忽略大小寫。

 

二、sed 命令

  sed( stream editor 流編輯器) ,可以用來在管道或者命令序列中編輯數據。sed 的語法如下:

sed option command file

  其中,command 是命令部分,用來指示 sed 該執行何種操作,file 則是 sed 命令將要操作的對象,通常是一個文件,如果沒有文件,則使用標準輸入。option 是 sed 命令可以使用的選項,主要有三個選項: -n、-e、-f,在後面再介紹。

  sed 命令讀取每一個文件,一次讀一行,將讀取的行放到記憶體的一個區域--稱為模式空間(pattern space),所有編輯上的操作都會應用到模式空間的內容。當所有操作完成後,sed 命令會將模式空間的最後內容列印到標準輸出,再回到開始處,讀取另一個輸入行。為了演示 sed 命令,筆者寫了一小段文本 test.txt 用作試驗的素材(英語差,語法問題請忽略)

hello,my name is tongye
I want to write a program named HelloWorld.c
now,let`s begin
#include "stdio.h"
main(){
        printf("Hello world");
}
oh,it`s symple
writed by tongye
end

2.1  使用 s 參數執行替換操作

  sed 命令一個常用的功能是進行替換操作,sed 替換操作的一般格式如下:

sed 's/string1/string2/' file    # 將文件中每行的第一個 string1 替換成 string2

  在上述語句中,參數 s 表示這是一個替換操作,/ 字元是界定符,用於分隔正則表達式與替代文本。界定符可以是任何可顯示的字元,但是 / 字元是最常用的界定符。另外,在處理文件名稱時,一般使用分號、冒號或逗號作為界定符。string1 是被替換的文本,可以是正則表達式;string2 是替換文本。

[tongye@localhost Shell_Program]$ sed 's/tongye/ttyezi/' test.txt 
hello,my name is ttyezi
I want to write a program named HelloWorld.c
now,let`s begin
#include "stdio.h"
main(){
        printf("Hello world");
}
oh,it`s symple
writed by ttyezi
end

   需要註意的是,上述語句只能替換第一個匹配到的文本,若想要將每一個匹配到的文本都替換掉,需要在結尾加上 g 參數(global),即:

sed 's/string1/string2/g' file    # 將文件中所有的 string1 都替換成 string2

  如果需要刪除文本中的一個字元串,可以在替換文本處不放入任何文本(即空)來實現,如下:

sed 's/string1//g' file               # 刪除文件中所有的 string1

 

2.2 使用 -e 選項和 -f 選項同時執行多個編輯命令

  當 sed 後面需要同時接多個編輯命令的時候,需要使用 -e 選項。每一個編輯命令都使用一個 -e 選項,如:

[tongye@localhost Shell_Program]$ sed -e 's/tongye/ttyezi/g' -e 's/HelloWorld/helloworld/g' test.txt
hello,my name is ttyezi
I want to write a program named helloworld.c
now,let`s begin
#include "stdio.h"
main(){
        printf("Hello world");
}
oh,it`s symple
writed by ttyezi
end

  當需要編輯的項目很多時,如果把每一個編輯命令都接到 sed 後面,無疑會讓代碼很複雜,不易閱讀且容易出錯。這時,可以將所有的編輯命令都寫進一個腳本,再使用 sed 搭配 -f 選項來操作:

# substitute.sed 存放著編輯命令 
s/tongye/ttyezi/g
s/HelloWorld/helloworld/g
s;^\(.\).*\1$;The first letter of this line is the same as its last letter;


[tongye@localhost Shell_Program]$ sed -f substitute.sed test.txt                                
hello,my name is ttyezi
I want to write a program named helloworld.c
The first letter of this line is the same as its last letter
#include "stdio.h"
main(){
        printf("Hello world");
}
oh,it`s symple
writed by ttyezi
end
View Code

 

2.3 使用 -n 選項與 p 參數列印特定的行

  sed 預設情況下會把輸入的每一行都列印到標準輸出上,如果不想輸出所有行,可以使用 -n 選項。使用了 -n 選項的 sed 命令將不列印任何行, -n 選項通常與參數 p 配合起來使用,p 參數可以讓 sed 命令列印出符合指定範圍或模式的所有行:

[tongye@localhost Shell_Program]$ sed -n 's/tongye/ttyezi/p' test.txt       
hello,my name is ttyezi
writed by ttyezi

  該語句將文件中的 tongye 替換成 ttyezi,並且只列印發生替換操作的兩行;

[tongye@localhost Shell_Program]$ sed -n '1,3p' test.txt        # 列印 1 到 3 行      
hello,my name is tongye
I want to write a program named HelloWorld.c
now,let`s begin

[tongye@localhost Shell_Program]$ sed -n '4p' test.txt       # 只列印第 4 行
#include "stdio.h"

  使用 sed -n '1,3p' 來只列印文件的前三行,註意這裡的 '1,3' 表示的是一個範圍;

[tongye@localhost Shell_Program]$ sed -n '/HelloWorld/p' test.txt 
I want to write a program named HelloWorld.c

  該命令只列印包含 HelloWorld 的行。

 

2.4 使用 d 參數執行刪除操作

  要刪除某一個特定的行,可以使用參數 d,只需要指定行號或者行範圍,就可以從輸入中刪除指定的行:

[tongye@localhost Shell_Program]$ sed '1,4d' test.txt      # 刪除第 1 到 4 行,然後將剩餘的行列印到標準輸出
main(){
        printf("Hello world");
}
oh,it`s symple
writed by tongye
end

   sed 也可以使用參數 d 來刪除符合匹配模式的行:

[tongye@localhost Shell_Program]$ sed '/tongye/d' test.txt     # 刪除所有含有 tongye 的行
I want to write a program named HelloWorld.c
now,let`s begin
#include "stdio.h"
main(){
        printf("Hello world");
}
oh,it`s symple
end

 

2.5 使用 -i 選項或輸出重定向來保存 sed 編輯的內容

  在上面的所有操作中,我們發現雖然 sed 操作確實完成了,輸出到標準輸出上的文本內容確實發生了變化,但是如果我們再次打開所編輯的文件,會發現文件內容並沒有發生更改。如果需要保存 sed 編輯的內容,可以使用 -i 選項:

[tongye@localhost Shell_Program]$ sed -i 's/tongye/ttyezi/' test.txt 
[tongye@localhost Shell_Program]$ cat test.txt                        
hello,my name is ttyezi
I want to write a program named HelloWorld.c
now,let`s begin
#include "stdio.h"
main(){
        printf("Hello world");
}
oh,it`s symple
writed by ttyezi
end
View Code

  也可以使用輸出重定向的方式,將編輯後的內容保存到一個新的文本文件中而不是輸出到標準輸出:

[tongye@localhost Shell_Program]$ sed 's/hello/HELLO/' test.txt > test1.txt 
[tongye@localhost Shell_Program]$ cat test1.txt 
HELLO,my name is ttyezi
I want to write a program named HelloWorld.c
now,let`s begin
#include "stdio.h"
main(){
        printf("Hello world");
}
oh,it`s symple
writed by ttyezi
end
View Code

 

三、awk 命令

3.1 awk 的基本模式與操作 

  shell 中提供 awk 命令來重新編排欄位。實際上, awk 本身所提供的功能十分完備,已經是一種很好用的程式語言了,這裡暫且只討論它在 shell 腳本中的一些長處:文本處理功能。awk 命令的基本模式如下:

awk 'program' [ file ...]

  awk 讀取命令行上所指定的各個文件(若沒有文件,則為標準輸入),一次讀取一條記錄(行),再針對每一行,應用 program 所指定的命令。 awk程式(program)基本架構為:

pattern {action}
pattern {action}
...

  pattern 部分幾乎可以是任何表達式,但是在單命令行程式里,它通常是由斜杠括起來的 ERE。 action 為任意的 awk 語句,但是在單命令行程式里,通常是一個直接明瞭的 print 語句。pattern 或 action 都可以省略(不要全部省略)。省略 pattern,則會對每一條輸入記錄執行 action;省略 action 則預設 action 為{ print } ,將列印顯示整條記錄。

[tongye@localhost etc]$ awk '/root/ {print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

  上述指令將列印文本中所有包含 root 的行。   

 

3.2 欄位

  awk 設計的重點就在欄位與記錄上:awk 讀取輸入記錄(通常是一些行),然後自動將各個記錄切分為欄位。awk 將每條記錄內的欄位數目,存儲到內建變數 NF 中。awk 預設以空白分隔欄位(如空格符、製表符),不過,也可以設置成其他的,通過設置 FS 變數(列數據分隔符)。如果需要使用欄位值,可以使用 $ 字元來引用,$1表示第一個欄位值、$2表示第二個欄位值、...  另外,$0表示整條記錄。舉個例子驗證一下:

[tongye@localhost Shell_Program]$ awk '{print $1}' test.txt 
hello,my
I
now,let`s
#include
main(){
printf("Hello
}
oh,it`s
writed
end

  這句指令將會按照預設的分隔符(空白符)來對欄位進行劃分,並列印第一個欄位的值到標準輸出。

 

3.3 設置欄位分隔符

  可以使用 -F 選項來修改欄位分隔符。-F 選項會自動的設置 FS 變數,只需將 FS 變數放到 -F 選項後面即可。FS 變數可以被設置為單個字元(此時,只要該字元出現一次,就分隔出一個欄位),也可以被設置為一個完整的 ERE(此時,每一個匹配該 ERE 的文本都將被視為欄位分隔符):

awk -F: '{print $1,$2}' /etc/passwd

  這段指令將使用冒號 : 作為欄位分隔符去處理 /etc/passwd 文件,然後輸出文件的第1、第2個欄位到標準輸出。

  -F 選項設置的欄位分隔符是相對於輸入而言的。而 awk 的輸入、輸出分隔符用法是分開的,因此即使使用 -F 選項設置了 FS 變數,輸出的欄位分隔符還是預設的空白符,這樣可能會影響結果判斷,使用 -v 選項可以設置輸出欄位分隔符,通過改變 OFS 變數(列數據輸出分隔符)的值,使用形式也 -F 選項有所區別:

awk -v 'OFS=/' '{print $1,$2}' /etc/passwd

  -v 選項的用法如上,該指令的將把 awk 的輸出與分隔符設置為斜杠符 / 。舉一個例子:

[tongye@localhost Shell_Program]$ awk -F '/..' -v 'OFS=/' '{ print $1,$2,$3 }' /etc/passwd
root:x:0:0:root:/ot:/n
bin:x:1:1:bin:/n:/in
daemon:x:2:2:daemon:/in:/in
adm:x:3:4:adm:/r/m:
lp:x:4:7:lp:/r/ool
sync:x:5:0:sync:/in:/n
shutdown:x:6:0:shutdown:/in:/in
halt:x:7:0:halt:/in:/in
mail:x:8:12:mail:/r/ool
operator:x:11:0:operator:/ot:/in
games:x:12:100:games:/r/mes:
ftp:x:14:50:FTP User:/r/p:
nobody:x:99:99:Nobody:/sbin/login
systemd-network:x:192:192:systemd Network Management:/sbin/login
dbus:x:81:81:System message bus:/sbin/login
polkitd:x:999:998:User for polkitd:/sbin/login
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/v/ll:
abrt:x:173:173::/c/rt:
sshd:x:74:74:Privilege-separated SSH:/r/pty
postfix:x:89:89::/r/ool
chrony:x:998:996::/r/b
tongye:x:1000:1000:tongye:/me/ngye:

  這段指令使用正則表達式 /.. 作為段分隔符去處理 /etc/passwd 文件,文件中每個匹配該正則表達式的文本都被視為一個欄位分隔符。然後使用斜杠符 / 作為輸出欄位分隔符,並將第1、2、3個欄位輸出到標準輸出。

 

3.4 列印行 print 與 printf

  print 上面已經用到過,這是 awk 裡面最常使用的一條語句,可以用來進行簡單的列印工作。print 的參數可以是欄位列表、變數或者字元串:

[tongye@localhost Shell_Program]$ awk -F: -v 'OFS=:' '{print "username is",$1}' /etc/passwd

  print 命令將後面的參數一個一個列印到標準輸出,如果沒有後接參數,則預設參數為 $0,將列印整條記錄。註意,print 的參數之間需要用逗號隔開,否則輸出結果將會連到一起沒有間隔。

  對於上面的語句,print 後面的參數混合了字元串和變數,當參數較多時,寫起來會比較不方便。此時,可以使用 printf 語句來替代 print 語句。printf 語句可以將所有參數放到一對雙引號中去,與 C 中的 printf 用法類似:

[tongye@localhost Shell_Program]$ awk -F: '{printf "username is %s\n",$1}' /etc/passwd
username is root
username is bin
username is daemon
username is adm
username is lp
username is sync
username is shutdown
username is halt
username is mail
username is operator
username is games
username is ftp
username is nobody
username is systemd-network
username is dbus
username is polkitd
username is tss
username is abrt
username is sshd
username is postfix
username is chrony
username is tongye

  需要註意的是,awk 的 print 語句會自動提供換行符,而 printf 語句不能,需要自己提供 \n 來進行換行。

 

參考資料:

《Linux 程式設計 第四版》

《Shell 腳本學習指南》

《UNIX/Linux/OS X 中的 Shell 編程 第四版》


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • OpenID Connect執行終端用戶登錄或確定終端用戶已經登錄的驗證工作。OpenID Connect 使伺服器以一種安全的方式返回驗證結果。所以客戶可以依靠它。出於這個原因,在這種情況下客戶被稱為依賴方(RP)。 驗證結果在返回ID令牌中,ID令牌定義(第二節)。它聲明表達這些信息作為發行人, ...
  • 為什麼使用依賴關係註入? 使用 .NET,通過 new 運算符(即,new MyService 或任何想要實例化的對象類型)調用構造函數即可輕鬆實現對象實例化。遺憾的是,此類調用會強制實施客戶端(或應用程式)代碼到已實例化對象的緊密耦合的連接(硬編碼的引用),此外還會引用其程式集/NuGet 包。對 ...
  • 目錄 一、 常量和欄位.... 1 1、 常量.... 1 2、欄位.... 1 二、方法.... 2 1、實例構造器和類(引用類型).... 2 2、實例構造器和結構(值類型).... 2 3、類型構造器.... 3 4、操作符重載方法.... 3 5、轉換操作符方法.... 3 6、擴展方法.. ...
  • /// /// 驗證 /// /// Account API賬號 /// TimeStamp 請求時間 /// Sign 所有請求參數 加密 public class AuthFilterOutside : AuthorizeAttribute { //重寫基類的驗證方式,加入我們自定義的Ticke... ...
  • 線程棧 stuck:存值類型,和引用類型的引用 先進後出,鏈表形式,連續擺放 CLR(公共語言運行庫(Common Language Runtime))啟動進程,main函數為一個線程入口 進程堆heap:存引用類型 進程中的一塊區域 IL:中間語言 對象的屬性為值類型出現在堆里,方法里的值類型,由 ...
  • 1,安裝Microsoft.AspNetCore.Mvc.Versioning NET Core Mvc中,微軟官方提供了一個可用的Api版本控制庫Microsoft.AspNetCore.Mvc.Versioning。 2,修改Startup類 這裡我們需要在Startup類的ConfigureS ...
  • 本人使用的是18款512g的macbookpro<後續簡稱mbp>,已升級最新mojave系統。 以下是我平時記錄、也是使用最多的快捷鍵,惠存。 1.切換拼音和字母 control+空格<或者直接按caps lock> 2.切換字母的大小寫dd 按住shift+字母-->大寫字母 3.撤銷 撤銷:c ...
  • 1. 輸出重定向 最基本的重定向是將命令的輸出發送到一個文件中。在bash shell中用大於號(>) ,格式如下:command > inputfile。例如:將date命令的輸出內容,保存到指定的輸出文件中。 如果文件已存在,重定向操作符會用新的文件數據覆蓋已有文件。這種情況下可以用雙大於號(> ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...