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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...