<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Linux:管道命令與文本處理三劍客(grep、sed、awk)

      1 管道命令(pipe)介紹

      眾所周知,bash命令執(zhí)行的時候會輸出信息,但有時這些信息必須要經(jīng)過幾次處理之后才能得到我們想要的格式,此時應(yīng)該如何處置?這就牽涉到 管道命令(pipe) 了。管道命令使用的是|這個界定符號。另外,管道命令與連續(xù)執(zhí)行命令是不一樣的,這點下面我們會說明。

      我們先來看一個管道命令的例子。假設(shè)我們需要看/etc目錄下有多少文件,那么可以利用ls /etc來查看,不過由于文件數(shù)量太多,導(dǎo)致一口氣就將屏幕塞滿了,而不知道前面輸出的內(nèi)容是啥:

      root@orion-orion:~ ls -al /etc                                                               
      total 944
      drwxr-xr-x 1 root root    4096 Feb 19 11:38 .
      drwxr-xr-x 1 root root    4096 Nov 23  2021 ..
      drwxr-xr-x 3 root root    4096 Jun  5  2021 .java
      ...
      drwxr-xr-x 2 root root    4096 Jul 24  2018 xfce4
      

      此時,我們可以使用less命令的協(xié)助:

      root@orion-orion:~ ls -al /etc | less 
      total 944
      drwxr-xr-x 1 root root    4096 Feb 19 11:38 .
      drwxr-xr-x 1 root root    4096 Nov 23  2021 ..
      drwxr-xr-x 3 root root    4096 Jun  5  2021 .java
      :
      

      如此一來,使用ls命令輸出的內(nèi)容就能夠被less讀取,并且利用less的功能,我們就能夠前后翻動相關(guān)的信息了。其中的關(guān)鍵就是這個管道命令|。管道命令|僅能處理前一個命令傳來的標(biāo)準(zhǔn)輸出信息,而對于標(biāo)準(zhǔn)錯誤信息并沒有直接處理能力。那么整體的管道命令可以使用下圖表示:

      在每個管道后面接的第一個數(shù)據(jù)必定是命令,而且這個命令必須要能夠接受標(biāo)準(zhǔn)輸出的數(shù)據(jù)才行,這樣的命令才可為管道命令。例如lessgrepsedawk等都是可以接受標(biāo)準(zhǔn)輸入的管道命令,而lscpmv就不是管道命令,因為它們并不會接受來自stdin的數(shù)據(jù)。總結(jié)一下,管道命令主要有兩個需要注意的地方:

      • 管道命令僅會處理標(biāo)準(zhǔn)輸出,對于標(biāo)準(zhǔn)錯誤會予以忽略
      • 管道命令必須要能夠接受來自前一個命令的數(shù)據(jù)成為標(biāo)準(zhǔn)輸入繼續(xù)處理才行(這也是其與由;隔開的連續(xù)執(zhí)行命令之不同)。

      如果我們強行讓標(biāo)準(zhǔn)錯誤為管道命令所用,那么可以使用2>&1將標(biāo)準(zhǔn)錯誤2>重定向到標(biāo)準(zhǔn)輸出1>

      接下來我們選取grepsedawk這三個用于文本處理的管道命令來進行介紹。這三個命令可謂是Linux下操作文本的三大利器,合稱Linux文本處理三劍客

      2 行選取命令grep

      grep命令可以一行一行地分析信息,若某行含有我們所需要的信息,則就將該行拿出來。簡單的語法如下:

      grep [-acinv] [--color=auto] '查找字符' filename
      

      它的選項與參數(shù)如下:

      • -a:將二進制文件以文本文件的方式查找數(shù)據(jù)。
      • -c:計算找到'查找字符'的次數(shù)。
      • -i:忽略大小寫的不同,所以大小寫視為相同。
      • -n:順便輸出行號。
      • -v:反向選擇,亦即顯示出沒有'查找字符'內(nèi)容的那些行。

      下面展示幾個例子。

      范例一:將last當(dāng)中,有出現(xiàn)root的那一行就顯示出來。

      root@orion-orion:~ last | grep 'root'
      root     pts/2        10.249.252.8     Mon Apr  6 06:08 - 09:02  (02:54)
      root     pts/1        10.249.252.8     Mon Apr  6 06:05 - 06:08  (00:03)
      root     pts/1        10.249.252.8     Mon Apr  6 03:13 - 06:05  (02:51)
      ...
      root     pts/1        :1               Tue Jul 24 06:44 - 06:45  (00:00)
      root     pts/1        172.17.0.1       Tue Apr 10 14:23 - 14:23  (00:00)
      root     pts/1        127.0.0.1        Tue Apr 10 08:57 - 08:57  (00:00)
      

      這里前3行是我們校內(nèi)的局域網(wǎng)IP(以10.249打頭),172.17.0.1是Docker中默認(rèn)網(wǎng)橋docker0的IP地址,127.0.0.1為本地回環(huán)地址。
      范例二:與范例一相反,只要沒有root的就取出。

      root@orion-orion:~ last | grep -v 'root'
      person   pts/1        127.0.0.1        Tue Apr 10 08:54 - 08:54  (00:00)
      

      范例三:在last的輸出信息中,只要有root就取出,并且僅取第一欄:

      root@orion-orion:~ last | grep "root" | awk '{print $1}' 
      root
      root
      root
      ...
      

      這里用到了我們后面要講的awk命令,這一命令用于將一行分為多個字段來處理,我們后面將會詳細(xì)介紹。
      范例四:取出/etc/adduser.conf內(nèi)含UID的那幾行,且將找到的關(guān)鍵字部分用特殊顏色顯示出來:

      root@orion-orion:~ grep --color=auto "UID" /etc/adduser.conf                                                                   
      # FIRST_SYSTEM_[GU]ID to LAST_SYSTEM_[GU]ID inclusive is the range for UIDs
      # package, may assume that UIDs less than 100 are unallocated.
      FIRST_SYSTEM_UID=100
      LAST_SYSTEM_UID=999
      # FIRST_[GU]ID to LAST_[GU]ID inclusive is the range of UIDs of dynamically
      FIRST_UID=1000
      LAST_UID=29999
      

      可以看到找到的關(guān)鍵字部分用紅色顯示(當(dāng)然這里的代碼塊看不出來效果,需要在終端進行渲染)。注意,在我的Ubuntu 18.04系統(tǒng)中默認(rèn)的grep已經(jīng)主動使用--color=auto選項在alias中了,因此不用手動加--color=auto也會標(biāo)紅(事實上,在我本地的Mac系統(tǒng)中也是如此)。

      3 行操作命令sed

      前面我們說過,grep命令可以解析一行文字,若該行含有某關(guān)鍵詞就會將其整行列出來。接下來我們要講的sed命令也是一個管道命令(可以分析標(biāo)準(zhǔn)輸入),它還可以對特定行進行新增、刪除、替換等sed的用法如下:

      sed [-nefr] [操作]
      

      它的選項與參數(shù)如下:

      • -n:使用安靜(silent)模式。在一般的sed用法中,所有來自stdin的數(shù)據(jù)一般都會被列出到屏幕上,但如果加上-n參數(shù)后,則只有經(jīng)過sed選擇的那些行才會被列出來。
      • -e:使sed的操作結(jié)果由屏幕輸出,而改變原有文件(默認(rèn)已選該參數(shù), 與-i的直接修改文件相反)。
      • -f:從一個文件內(nèi)讀取將要執(zhí)行的sed操作,-f filename可以執(zhí)行filename中寫好的sed操作。
      • -rsed的操作使用的是擴展型正則表達式的語法(默認(rèn)是基礎(chǔ)正則表達式語法)。
      • -i:直接修改讀取的文件內(nèi)容,而不是由屏幕輸出。

      關(guān)于其中的[操作]部分,其格式如下:

      [n1[,n2]]function
      

      n1, n2:不一定會存在,一般代表選擇進行操作的行數(shù),比如我的操作需要在10到20行之間進行,則寫為10, 20[操作名稱]

      具體地,對行的操作函數(shù)function包括下面這些東西:

      • a:新增,a的后面可以接字符,這些字符將被添加在n1/n2下一行
      • c:替換,c的后面可以接字符,這些字符可以替換n1n2之間的行;
      • d:刪除,因為是刪除,所以d后面通常不需要接任何東西;
      • i:插入,i的后面可以接字符,這些字符將被添加在n1/n2上一行
      • p:打印,亦即將某些選擇的行打印出來。通常p會與參數(shù)sed -n一起運行。
      • s:替換,可以直接進行替換的工作,通常這個s的操作可以搭配正則表達式。

      下面我們來舉幾個例子進行說明。

      以行為單位的新增/刪除功能

      范例一:查看/etc/passwd文件的內(nèi)容并且在每一行前面加上行號,同時將2-5行刪除。

      root@orion-orion:~ cat -n /etc/passwd | sed '2,5d'
          1  root:x:0:0:root:/root:/bin/zsh
          6  games:x:5:60:games:/usr/games:/usr/sbin/nologin
          7  man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
          8  lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
          ...
      

      可以看到sed的操作為2,5d,也即刪除2~5行,所以顯示的數(shù)據(jù)就沒有2~5行。此外,請注意原本應(yīng)該是要執(zhí)行sed -e才對,不過這里沒有-e也行,因為已經(jīng)默認(rèn)選了。同時也要注意sed后面接的操作務(wù)必以兩個單引號''括住。

      我們將范例變一下,如果要刪除第2行,那么可以使用cat -n /etc/passwd | sed '2d' ;如果是要刪除第3到最后一行,則是cat -n /etc/passwd | sed '3,$d',這里美元符號$代表最后一行。

      范例二: 承接上題,在第2行后(亦即是第3行)加上drink tea字樣。

      root@orion-orion:~ cat -n /etc/passwd | sed '2a Drink tea?'
           1  root:x:0:0:root:/root:/bin/zsh
           2  daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
      Drink tea?
           3  bin:x:2:2:bin:/bin:/usr/sbin/nologin
           ...
      

      如果想要加在第2行前面,將新增操作改為插入操作,即cat -n /etc/passwd | sed '2i Drink tea?'就行了。

      范例三:繼續(xù)承接上題,現(xiàn)在我們想要在第2行后面加上兩行字,例如Drink tea or...Drink beer?

      root@orion-orion:~ cat -n /etc/passwd | sed '2a Drink tea or...\                                                  
      \ Drink beer?'
           1  root:x:0:0:root:/root:/bin/zsh
           2  daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
      Drink tea or...
      Drink beer?
           3  bin:x:2:2:bin:/bin:/usr/sbin/nologin
      

      這里的重點在于我們可以不只增加一行,可以增加很多行,但每一行之間必須以反斜杠\來進行新行的增加。

      以行為單位的替換與顯示功能

      剛剛是介紹如何新增與刪除行。接下來我們看看如何進行整行的替換。

      范例四:我想將2~5行的內(nèi)容替換為No 2-5 number

      root@orion-orion:~ cat -n /etc/passwd | sed '2,5c No 2-5 number`   
           1  root:x:0:0:root:/root:/bin/zsh
      No 2-5 number
           6  games:x:5:60:games:/usr/games:/usr/sbin/nologin
           ...
      

      除此之外,sed還有很有趣的功能,以前我們想要列出第11~25行,得用head -n 20tail -n 10之類的命令來處理,很麻煩。而sed則可以直接取出你想要的那幾行,這是通過行號來識別的。例如下面這個范例:

      范例五:僅列出/etc/passwd文件內(nèi)的第5-7行。

      root@orion-orion:~ cat -n /etc/passwd | sed -n '5,7p'
           5  sync:x:4:65534:sync:/bin:/bin/sync
           6  games:x:5:60:games:/usr/games:/usr/sbin/nologin
           7  man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
      

      注意,這里必須要加-n表示安靜模式。如果不加-n改為sed 5,7p,那么第5-7行會重復(fù)輸出:

      root@orion-orion:~ cat -n /etc/passwd | sed '5,7p'
           1  root:x:0:0:root:/root:/bin/zsh
           2  daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
           3  bin:x:2:2:bin:/bin:/usr/sbin/nologin
           4  sys:x:3:3:sys:/dev:/usr/sbin/nologin
           5  sync:x:4:65534:sync:/bin:/bin/sync
           5  sync:x:4:65534:sync:/bin:/bin/sync
           6  games:x:5:60:games:/usr/games:/usr/sbin/nologin
           6  games:x:5:60:games:/usr/games:/usr/sbin/nologin
           7  man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
           7  man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
           8  lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
           ...
      

      部分?jǐn)?shù)據(jù)的查找并替換的功能

      除了整行的處理模式之外,sed還可以對某行進行部分?jǐn)?shù)據(jù)的查找和替換。基本上sed的查找與替換與vi相當(dāng)?shù)念愃疲母袷饺缦滤荆?/p>

      sed 's/要被替換的字符/新的字符/g'
      

      接下來我們來看一個取得IP數(shù)據(jù)的范例,我們將該任務(wù)拆解為多步,一段一段地處理。

      步驟一:先觀察原始信息,利用/sbin/ifconfig查詢IP是什么?

      root@orion-orion:~ /sbin/ifconfig eth0
      eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:0c  
                inet addr:172.17.0.12  Bcast:172.17.255.255  Mask:255.255.0.0
                UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
                RX packets:49498631 errors:0 dropped:0 overruns:0 frame:0
                TX packets:41131666 errors:0 dropped:0 overruns:0 carrier:0
                collisions:0 txqueuelen:0 
                RX bytes:51467728818 (51.4 GB)  TX bytes:40995045195 (40.9 GB)
      

      我們希望用關(guān)鍵詞識別出172.17.0.12,這是我所用學(xué)校服務(wù)器的內(nèi)網(wǎng)私有IP地址。

      步驟二:利用關(guān)鍵字配合grep選取出inet所在的那關(guān)鍵的一行。

      root@orion-orion:~ /sbin/ifconfig eth0 | grep 'inet '
                inet addr:172.17.0.12  Bcast:172.17.255.255  Mask:255.255.0.0
      

      好了,現(xiàn)在只剩下一行了,但我們想只留下IP地址addr:172.17.0.12而將其它部分統(tǒng)統(tǒng)刪除。

      步驟三:先將IP前面的部分予以刪除(用到正則表達式)。

      root@orion-orion:~ /sbin/ifconfig eth0 | grep 'inet ' | sed 's/^.*inet //g'
      addr:172.17.0.12  Bcast:172.17.255.255  Mask:255.255.0.0
      

      這里正則表達式中的^表示待查找的字符串在行首;.表示一定有一個任意字符,*表示重復(fù)前一個字符0到無窮多次,連在一起的.*就表示任意字符重復(fù)任意次;//之間為空,也就表示刪除的意思。

      步驟四:將IP后面的部分也予以刪除。

      root@orion-orion:~ /sbin/ifconfig eth0 | grep 'inet ' | sed 's/^.*inet //g' \
      \ | sed 's/ *Bcast.*$//g' 
      addr:172.17.0.12
      

      這里' *'表示空格重復(fù)任意次;.*表示任意字符重復(fù)任意次;$表示待查找的字符串在行尾。

      我們再來繼續(xù)研究sed與正則表達式的配合練習(xí)。假設(shè)我們只要/etc/adduser.conf 文件中UID存在的那幾行數(shù)據(jù),但是有#在內(nèi)的注釋我們不要,而且空白行我們也不要,那么應(yīng)該如何處理?可以通過這幾個步驟來實踐看看:

      步驟一:先用grep將關(guān)鍵字UID所在行取出來。

      root@orion-orion:~ cat /etc/adduser.conf  | grep 'UID'
      # FIRST_SYSTEM_[GU]ID to LAST_SYSTEM_[GU]ID inclusive is the range for UIDs
      # package, may assume that UIDs less than 100 are unallocated.
      FIRST_SYSTEM_UID=100
      LAST_SYSTEM_UID=999
      # FIRST_[GU]ID to LAST_[GU]ID inclusive is the range of UIDs of dynamically
      FIRST_UID=1000
      LAST_UID=29999
      

      步驟二:刪除掉注釋之后的內(nèi)容:

      root@orion-orion:~ cat /etc/adduser.conf | grep 'UID' | sed 's/#.*$//g' 
      
      
      FIRST_SYSTEM_UID=100
      LAST_SYSTEM_UID=999
      
      FIRST_UID=1000
      LAST_UID=29999
      

      這樣原本注釋的內(nèi)容都變成了空白行,接下來我們刪除空白行:

      root@orion-orion:~ cat /etc/adduser.conf | grep 'UID' | sed 's/#.*$//g' | sed '/^$/d'
      FIRST_SYSTEM_UID=100
      LAST_SYSTEM_UID=999
      FIRST_UID=1000
      LAST_UID=29999
      

      注意這里的^$表示行首^和行尾$之間沒有字符,也即空白行。

      直接修改文件內(nèi)容(危險操作)

      sed的能耐可不止于我們上面所說的,它甚至可以直接修改文件的內(nèi)容,而不必使用管道命令或數(shù)據(jù)流重定向。不過這個操作會修改到原始的文件,所以請你千萬不要隨便拿系統(tǒng)配置文件來測試。我們下面使用regular_express.txt文件來測試(文件可以去鳥哥的官網(wǎng)下載:regular_express.txt)。

      root@orion-orion:~ cat regular_express.txt                                                                     
      "Open Source" is a good mechanism to develop programs.
      apple is my favorite food.
      Football game is not use feet only.
      this dress doesn't fit me.
      ...
      go! go! Let's go.
      # I am VBird
      

      范例六:利用sedregular_express.txt內(nèi)每一行結(jié)尾若為.則換成!

      root@orion-orion:~ sed -i 's/\.$/\!/g' regular_express.txt
      root@orion-orion:~ cat regular_express.txt
      "Open Source" is a good mechanism to develop programs!
      apple is my favorite food!
      Football game is not use feet only!
      this dress doesn't fit me!
      ...
      go! go! Let's go!
      # I am VBird
      

      上面的-i選項可以讓你的sed直接去修改后面所接的文件內(nèi)容而不是由屏幕輸出。

      范例七:利用sed直接在regular_express.txt最后一行加入# This is a test

      root@orion-orion:~ sed -i '$a # This is a test' regular_express.txt
      root@orion-orion:~ tail regular_express.txt
      ...
      go! go! Let's go!
      # I am VBird
      
      # This is a test
      

      由于$代表的是最后一行,而a的操作是新增,因此是該文件最后新增。

      sed-i選項可以直接修改文件內(nèi)容,因此這功能非常有幫助。比如如果你有一個100萬行的文件,你要在第100行加某些文字,此時使用vim可能會瘋掉,因為文件太大了。此時就可以利用sed來直接修改與替換,而不需要使用vim去修改了。

      4 字段操作命令awk

      相較于sed常常對一整行進行操作,awk則傾向于將一行分為多個字段來處理。因此,awk相當(dāng)適合處理小型的文本數(shù)據(jù),其運行模式通常是這樣的:

      awk '{條件類型1{操作1} 條件類型2{操作2} ...}' filename
      

      awk后接兩個單引號并加上大括號{}來設(shè)置想要對數(shù)據(jù)進行的處理操作。awk可以處理后續(xù)接的文件,也可以讀取來自前一個命令的標(biāo)準(zhǔn)輸出。如前面所說,awk主要是將每一行分為多個字段來處理,而默認(rèn)的字段分隔符為空格鍵[Tab]鍵。舉例來說,我們用last將登陸者的數(shù)據(jù)取出來(僅取出前3行):

      root@orion-orion:~ last -n 3
      root     pts/292      10.249.45.37     Wed Mar 29 06:55 - 09:14  (02:19)
      root     pts/292      10.249.45.37     Tue Mar 28 13:17 - 16:14  (02:56)
      root     pts/292      10.249.45.37     Tue Mar 28 12:35 - 13:17  (00:42)
      
      wtmp begins Tue Apr 10 08:54:45 2018
      

      若我想取出賬號與登陸者的IP,且賬號與IP之間以[Tab]隔開,則會變成這樣:

      root@orion-orion:~ last -n 3 | awk '{print $1 "\t" $3}'                                                        
      root    10.249.45.37
      root    10.249.45.37
      root    10.249.45.37
      

      注意,awk的所有后續(xù)操作都是以單引號括住的,而awk的格式內(nèi)容如果想要以print打印時,記得將非變量的文字部分使用雙引號括起來,因為單引號已經(jīng)是awk命令的固定用法了。此外,因為這里無論哪一行我們都要處理,因此就不需要有條件類型的限制。

      另外,由上面的例子我們看到,在awk的括號內(nèi),每一行的每個字段都有變量名稱($1$2等)。在上面的例子中,root位于第1欄,故其變量名稱為$1;而10.249.45.37是第3欄,故它是$3,后面以此類推。還有個變量比較特殊,那就是$0,它表示一整行數(shù)據(jù)。由此可知,剛剛上面5行當(dāng)中,整個awk的處理流程就是:

      1. 一次性讀入第1行整行的數(shù)據(jù)并存入$0,然后將其拆分為多個字段并寫入$1$2$3等變量當(dāng)中。
      2. 根據(jù)條件類型的限制,判斷是否需要進行后面的操作(在上面這個例子中沒有條件類型)。
      3. 完成所有操作與條件類型。
      4. 若還有后續(xù)行的數(shù)據(jù),則重復(fù)上面1~3的步驟,直到所有的數(shù)據(jù)都讀完為止。
        經(jīng)過這樣的步驟,我們看到了awk以行為一次處理的單位,而以字段為最小的處理單位。好了,那么如何快速地獲得我們的數(shù)據(jù)有幾行幾列呢?這就需要awk的內(nèi)置變量的幫忙。
      變量名稱 代表意義
      NF 每一行(也即$0)所擁有的字段總數(shù)
      NR 目前awk所處理的是第幾行數(shù)據(jù)
      FS 目前的分割字符,默認(rèn)是空格鍵

      我們繼續(xù)以上面last -n 3的例子來做說明,如果我想要:

      • 列出每一行的賬號(也就是$1);
      • 列出目前處理的行數(shù)(就是awk內(nèi)的NR變量);
      • 并且說明該行有多少字段(也就是awk內(nèi)的NF字段);

      則可以這樣:

      root@orion-orion:~ last -n 5 | awk '{print $1 "\t lines: " NR "\t columns: " NF}'
      root     lines: 1        columns: 10
      root     lines: 2        columns: 10
      root     lines: 3        columns: 10
               lines: 4        columns: 0
      wtmp     lines: 5        columns: 7
      

      注意,在awk內(nèi)的NRNF等變量要用大寫,且不需要有美元符號$

      接下來我們來看一看所謂的“條件類型”。

      awk 的邏輯運算字符
      既然要用到“條件”的類別,那么自然就需要一些邏輯運算,如下所示:

      運算單元 代表意義
      > 大于
      < 小于
      >= 大于或等于
      <= 小于或等于
      == 等于
      != 不等于

      注意,邏輯運算即所謂的大于、小于等于等判斷式上面,習(xí)慣上用==而不是=來表示,=符號在awk操作這里留給了變量賦值用。

      我們來看下面一個例子。比如在/etc/passwd中是以冒號:來作為字段的分隔,該文件中第一字段為賬號,第三字段為UID。如下所示:

      root@orion-orion:~ cat /etc/passwd | less                                                                      
      root:x:0:0:root:/root:/bin/zsh
      daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
      bin:x:2:2:bin:/bin:/usr/sbin/nologin
      ...
      dnsmasq:x:115:65534:dnsmasq,,,:/var/lib/misc:/bin/false
      

      那假設(shè)我要查看第三欄小于10的數(shù)據(jù),并且僅列出賬號與第三列,那么可以這樣做:

      root@orion-orion:~ cat /etc/passwd | awk '{FS=":"} $3 < 10 {print $1 "\t " $3}'
      root:x:0:0:root:/root:/bin/zsh   
      daemon   1
      bin      2
      ...
      

      誒,不過怎么第一行沒有正確地顯示出來?這是因為我們在讀入第一行的時候,那些變量$1$2等等默認(rèn)還是以空格鍵做為分割,所以雖然我們定義了FS=":",但卻僅能在第二行后才開始生效。那怎么辦呢?我們可以預(yù)先設(shè)置awk的變量,利用BEGIN這個關(guān)鍵詞,這樣做:

      root@orion-orion:~ cat /etc/passwd | awk 'BEGIN {FS=":"} $3 < 10 {print $1 "\t " $3}'
      root     0
      daemon   1
      bin      2
      ...
      

      接下來我們來看如何用awk來完成計算功能。

      假設(shè)我們有一個薪資數(shù)據(jù)表文件為pay.txt,內(nèi)容如下:

      root@orion-orion:~ cat pay.txt
      Name    1st     2nd     3th
      VBird   23000   24000   25000
      DMTsai  21000   20000   23000
      Bird2   43000   42000   41000
      

      如何來計算每個人1st2nd3th的總額呢?而且我們還需要格式化輸出。我們可以這樣考慮:

      • 第一行只是表頭,所以第一行不進行求和而僅需要對表頭進行打印(也即NR==1時處理)。
      • 第二行以后進行求和(NR>=2以后處理)。
      root@orion-orion:~ cat pay.txt | \
      awk 'NR == 1 {printf "%10s %10s %10s %10s %10s\n", $1, $2, $3, $4, "Total"} \
      NR >= 2 {total = $2 + $3 + $4; \
      printf "%10s %10d %10d %10d %10.2f\n", $1, $2, $3, $4, total}'
            Name        1st        2nd        3th      Total
           VBird      23000      24000      25000   72000.00
          DMTsai      21000      20000      23000   64000.00
           Bird2      43000      42000      41000  126000.00
      

      上面的例子有幾個重要事項應(yīng)該要先說明:

      • awk的命令間隔:所有awk的操作,亦即在{}里的操作,如果有需要多個命令輔助時,可利用分號;間隔。
      • 邏輯運算中,如果是“等于”的情況,請務(wù)必使用==
      • 格式化輸出時,在printf的格式設(shè)置中,務(wù)必加上\n,才能分行(這里注意可以和Python的print函數(shù)和shell的echo函數(shù)做對比,此二者自帶換行);
      • 與bash shell中的變量不同,awk中的變量可以直接使用,不需要加上$符號。

      另外,awk的操作內(nèi){}也是支持if( 條件 )的,比如上面的命令也可以寫為:

      root@orion-orion:~ cat pay.txt | \
      awk '{if (NR == 1) printf "%10s %10s %10s %10s %10s\n", $1, $2, $3, $4, "Total"} \
      NR >= 2 {total = $2 + $3 + $4; \
      printf "%10s %10d %10d %10d %10.2f\n", $1, $2, $3, $4, total}'
            Name        1st        2nd        3th      Total
           VBird      23000      24000      25000   72000.00
          DMTsai      21000      20000      23000   64000.00
           Bird2      43000      42000      41000  126000.00
      

      第一種寫法相較于第二種寫法更好,因為比較有統(tǒng)一性。

      除此之外,awk還可以幫我們進行循環(huán)計算,不過那屬于比較高級的單獨課程了,這里就不再多加以介紹。

      5 習(xí)題

      情景模擬題一

      通過grep配合子命令$(command)來從大量文件中查找含有星號*的文件與內(nèi)容。

      1. 我們先來看如何在/etc下面找出含有星號*的文件與內(nèi)容。
      root@orion-orion:~ grep '\*' /etc/* 2> /dev/null  
      /etc/adduser.conf:#NAME_REGEX="^[a-z][-a-z0-9_]*\$"
      /etc/bash.bashrc:#xterm*|rxvt*)
      /etc/bash.bashrc:#*)
      ...
      

      注意,這里單引號''內(nèi)的型號是正則表達式的字符,但由于我們要找的是星號,因此需要加上轉(zhuǎn)義符\;而/etc/*的那個*是bash通配符中的“萬用字符”,在這里代表擁有任意多個字符的文件名。

      不過在上述的這個例子中,我們僅能找到/etc下第一層子目錄的數(shù)據(jù),無法找到次目錄的數(shù)據(jù)。如果想要連同完整的/etc此目錄數(shù)據(jù),就得要這樣做:

      root@orion-orion:~ grep '\*' $(find /etc -type f) 2> /dev/null
      Binary file /etc/ld.so.cache matches
      /etc/xdg/xfce4/xinitrc:  for i in ${XDG_CONFIG_HOME}/autostart/*.desktop; do
      /etc/xdg/xfce4/xinitrc: x|xno*)
      /etc/xdg/xfce4/xinitrc: *)
      ...
      

      如果只想列出文件名而不想列出內(nèi)容的話,可以加個-l參數(shù):

      root@orion-orion:~ grep -l '\*' $(find /etc -type f) 2> /dev/null
      /etc/ld.so.cache
      /etc/xdg/xfce4/xinitrc
      /etc/xdg/Thunar/uca.xml
      /etc/skel/.bashrc
      ...
      
      1. 又是文件數(shù)量會太多,比如如果我們要找的是全系統(tǒng)/的話:
      root@orion-orion:~ grep '\*' $(find / -type f) 2> /dev/null  
      

      蕪湖,一運行這個命令,由于要打印的東西太多,終端直接卡死。這下該如何是好呢?此時我們可以通過管道命令以及xargs來處理。比如,讓grep每次僅能處理10個文件名,我們可以:

      a. 先用find去找出文件;
      b. 用xargs將這些文件每次丟10個給grep來作為參數(shù)處理;
      c. grep實際開始查找文件內(nèi)容;

      所以整個做法會變成這樣:

      root@orion-orion:~ find / -type f 2> /dev/null | xargs -n 10 grep '\*'
      Binary file /sbin/chcpu matches
      Binary file /sbin/sulogin matches
      Binary file /sbin/pivot_root matches
      ...
      

      然而,從輸出的結(jié)果看,數(shù)據(jù)量實在非常龐大,如果我們只想知道文件名的話也可以給grep加上-l參數(shù):

      root@orion-orion:~ find / -type f 2> /dev/null | xargs -n 10 grep -l '\*'
      /sbin/chcpu
      /sbin/sulogin
      /sbin/pivot_root
      ...
      

      情景模擬題二

      使用管道命令配合正則表達式建立新命令與新變量。我們想要建立一個名為myip的新命令,這個命令能夠?qū)⑽蚁到y(tǒng)的IP識別出來并顯示。而且我們想要有個新變量MYIP來記錄我們的IP。

      處理的方式如下所示:

      1. 首先根據(jù)我們前面所講的ifconfigsedawk來取得我們的IP:
      root@orion-orion:~ ifconfig eth0 | grep 'inet ' | sed 's/^.*inet //g' | sed 's/ *Bcast.*$//g'
      addr:172.17.0.12
      
      1. 接著,我們可以將此命令利用alias指定為myip,如下所示:
      root@orion-orion:~ alias myip="ifconfig eth0 | grep 'inet ' | sed 's/^.*inet //g' | \
      \ sed 's/ *Bcast.*$//g'"
      root@orion-orion:~ myip
      addr:172.17.0.12
      
      1. 最終,我們可以通過變量設(shè)置來處理MYIP
      root@orion-orion:~ MYIP=$(myip) 
      root@orion-orion:~ echo $MYIP
      addr:172.17.0.12
      
      1. 如果每次登陸都要生效,可以將aliasMYIP設(shè)置的那兩行寫入你的~/.bashrc即可。

      參考

      • [1] 鳥哥. 鳥哥的 Linux 私房菜: 基礎(chǔ)學(xué)習(xí)篇(第四版)[M]. 人民郵電出版社, 2018.
      posted @ 2023-04-18 00:26  orion-orion  閱讀(3684)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 久久青青草原精品国产app| 亚洲黄色一级片在线观看| 国产a在视频线精品视频下载| 国产黄色一区二区三区四区| 99久久er热在这里只有精品99| 看全色黄大色黄大片 视频| 亚洲午夜av一区二区| 精品无码一区二区三区电影| 丰满少妇在线观看网站| 久久精品国产清自在天天线| 久久国产精品成人免费| 国内精品久久久久影视| 无码精品人妻一区二区三李一桐| 中国少妇人妻xxxxx| 在线a级毛片无码免费真人| 泰安市| 亚洲线精品一区二区三八戒| 国产精品一区二区三区黄| 中文字幕亚洲综合第一页| 男人的天堂va在线无码| 久久综合精品国产一区二区三区无 | 亚洲av日韩av永久无码电影| 玛多县| 亚洲精品久久无码av片软件| 午夜免费福利小电影| 久久99久久99精品免视看国产成人| 一级片一区二区中文字幕| 疯狂三人交性欧美| 亚洲av色一区二区三区| 亚洲国产超清无码专区| 在线看国产精品自拍内射 | 免费看婬乱a欧美大片| 18禁美女裸体爆乳无遮挡| 亚洲国产精品日韩专区av| 国产精品成人观看视频国产奇米| 国产成人高清亚洲一区91| 亚洲大尺度无码专区尤物| 国产成人亚洲综合图区| 亚洲AV成人片不卡无码| 午夜一区二区三区视频| 国产91麻豆视频免费看|