sed教程入門與實例練習(三)

在第二篇 sed 文章中,我提供了一些示例來演示 sed 的工作原理,但是它們當中很少有示例能實際做特別有用的事。在這篇 sed 系列的最后文章中,我要改變那種方式,并使用 sed 來做實際的事。我將為您顯示幾個示例,它們不僅演示 sed 的能力,而且還做一些真正巧妙(和方便)的事。例如,在本文的后半部,將為您演示如何設計一個 sed 腳本來將 .QIF 文件從 Intuit 的 Quicken 金融程序轉換成具有良好格式的文本文件。在那樣做之前,我們將看一下不怎么復雜但卻很有用的 sed 腳本。

文本轉換
第一個實際腳本將 UNIX 風格的文本轉換成 DOS/Windows 格式。您可能知道,基于 DOS/Windows 的文本文件在每一行末尾有一個 CR(回車)和 LF(換行),而 UNIX 文本只有一個換行。有時可能需要將某些 UNIX 文本移至 Windows 系統,該腳本將為您執行必需的格式轉換。

$ sed -e ’s/$//r/’ myunix.txt > mydos.txt

在該腳本中,’$’ 規則表達式將與行的末尾匹配,而 ‘/r’ 告訴 sed 在其之前插入一個回車。在換行之前插入回車,立即,每一行就以 CR/LF 結束。請注意,僅當使用 GNU sed 3.02.80 或以后的版本時,才會用 CR 替換 ‘/r’。如果還沒有安裝 GNU sed 3.02.80,請在我的第一篇 sed 文章中查看如何這樣做的說明。

我已記不清有多少次在下載一些示例腳本或 C 代碼之后,卻發現它是 DOS/Windows 格式。雖然很多程序不在乎 DOS/Windows 格式的 CR/LF 文本文件,但是有幾個程序卻在乎 — 最著名的是 bash,只要一遇到回車,它就會出問題。以下 sed 調用將把 DOS/Windows 格式的文本轉換成可信賴的 UNIX 格式:

$ sed -e ’s/.$//’ mydos.txt > myunix.txt

該腳本的工作原理很簡單:替代規則表達式與一行的最末字符匹配,而該字符恰好就是回車。我們用空字符替換它,從而將其從輸出中徹底刪除。如果使用該腳本并注意到已經刪除了輸出中每行的最末字符,那么,您就指定了已經是 UNIX 格式的文本文件。也就沒必要那樣做了!

反轉行
下面是另一個方便的小腳本。與大多數 Linux 發行版中包括的 “tac” 命令一樣,該腳本將反轉文件中行的次序。”tac” 這個名稱可能會給人以誤導,因為 “tac” 不反轉行中字符的位置(左和右),而是反轉文件中行的位置(上和下)。用 “tac” 處理以下文件:

foo bar oni

….將產生以下輸出:

oni bar foo

可以用以下 sed 腳本達到相同目的:

$ sed -e ‘1!G;h;$!d’ forward.txt > backward.txt

如果登錄到恰巧沒有 “tac” 命令的 FreeBSD 系統,將發現該 sed 腳本很有用。雖然方便,但最好還是知道該腳本為什么那樣做。讓我們對它進行討論。

反轉解釋
首先,該腳本包含三個由分號隔開的單獨 sed 命令:’1!G’、’h’ 和 ‘$!d’。現在,需要好好理解用于第一個和第三個命令的地址。如果第一個命令是 ‘1G’,則 ‘G’ 命令將只應用第一行。然而,還有一個 ‘!’ 字符 — 該 ‘!’ 字符忽略該地址,即,’G’ 命令將應用到除第一行之外的所有行。’$!d’ 命令與之類似。如果命令是 ‘$d’,則將只把 ‘d’ 命令應用到文件中的最后一行(’$’ 地址是指定最后一行的簡單方式)。然而,有了 ‘!’ 之后,’$!d’ 將把 ‘d’ 命令應用到除最后一行之外的所有行。現在,我們所要理解的是這些命令本身做什么。

當對上面的文本文件執行反轉腳本時,首先執行的命令是 ‘h’。該命令告訴 sed 將模式空間(保存正在處理的當前行的緩沖區)的內容復制到保留空間(臨時緩沖區)。然后,執行 ‘d’ 命令,該命令從模式空間中刪除 “foo”,以便在對這一行執行完所有命令之后不打印它。

現在,第二行。在將 “bar” 讀入模式空間之后,執行 ‘G’ 命令,該命令將保留空間的內容 (”foo/n”) 附加到模式空間 (”bar/n”),使模式空間的內容為 “bar/n/foo/n”。’h’ 命令將該內容放回保留空間保護起來,然后,’d’ 從模式空間刪除該行,以便不打印它。

對于最后的 “oni” 行,除了不刪除模式空間的內容(由于 ‘d’ 之前的 ‘$!’)以及將模式空間的內容(三行)打印到標準輸出之外,重復同樣的步驟。

現在,要用 sed 執行一些強大的數據轉換。

sed QIF 魔法
過去幾個星期,我一直想買一份 Quicken 來結算我的銀行帳戶。Quicken 是一個非常好的金融程序,當然會成功地完成這項工作。但是,經過考慮之后,我覺得自己可以輕易編寫某個軟件來結算我的支票簿。我想,畢竟,我是個軟件開發人員!

我開發了一個很好的小型支票簿結算程序(使用 awk),它通過分析包含我的所有交易的文本文件的語法來計算余額。略微調整之后,我將其改進,以便可以象 Quicken 那樣跟蹤不同的貸款和借款類別。但是,我還要添加一個特性。最近,我將帳戶轉移到一家有聯機 Web 帳戶界面的銀行。有一天,我注意到,這家銀行的 Web 站點允許以 Quicken 的 .QIF 格式下載我的帳戶信息。我馬上覺得,如果可以將該信息轉換成文本格式,那就太棒了。

兩種格式的故事
在查看 QIF 格式之前,先看一下我的 checkbook.txt 格式:

28 Aug 2000 food - - Y Supermarket 30.94 25 Aug 2000 watr - 103 Y Check 103 52.86

在我的文件中,所有字段都由一個或多個制表符分開,每個交易占據一行。日期之后的下一個字段列出支出類型(如果是收入項,則為 “-”)。第三個字段列出收入類型(如果是支出項,則為 “-”)。然后,是一個支票號字段(如果為空,則還是 “-”),一個交易完成字段(”Y” 或 “N”),一個注釋和一個美元金額字段。現在,讓我們看一下 QIF 格式。當用文本查看器查看下載的 QIF 文件時,它看起來如下:

!Type:Bank D08/28/2000 T-8.15 N PCHECKCARD SUPERMARKET ^ D08/28/2000 T-8.25 N PCHECKCARD PUNJAB RESTAURANT ^ D08/28/2000 T-17.17 N PCHECKCARD SUPERMARKET

瀏覽過文件之后,不難猜出其格式 — 忽略第一行,其余的格式如下:

D<數據>
T<交易量>
N<支票號>
P<描述>
^ (這是字段分隔符)

開始處理
在處理象這樣重要的 sed 項目時,不要氣餒 — sed 允許您將數據逐漸修改成最終形式。在進行當中,可以繼續細化 sed 腳本,直到輸出與預期的完全一樣為止。無需在試第一次時就保證其完全正確。

要開始,首先創建一個名為 “qiftrans.sed” 的文件,然后開始修改數據:

1d /^^/d s/[[:cntrl:]]//g

第一個 ‘1d’ 命令刪除第一行,第二個命令從輸出除去那些討厭的 ‘^’ 字符。最后一行除去文件中可能存在的任何控制字符。既然在處理外來文件格式,我想消除在中途遇到任何控制字符的風險。到目前為止,一切順利。現在,要向該基本腳本中添加一些處理功能:

1d /^^/d s/[[:cntrl:]]//g /^D/ {
s/^D/(.*/)//1/tOUTY/tINNY/t/
s/^01/Jan/ s/^02/Feb/
s/^03/Mar/ s/^04/Apr/
s/^05/May/ s/^06/Jun/
s/^07/Jul/ s/^08/Aug/
s/^09/Sep/ s/^10/Oct/
s/^11/Nov/ s/^12/Dec/
s:^/(.*/)//(.*/)//(.*/):/2 /1 /3: }

首先,添加一個 ‘/^D/’ 地址,以便 sed 只在遇到 QIF 數據字段的第一個字符 ‘D’ 時才開始處理。當 sed 將這樣一行讀入其模式空間時,將按順序執行花括號中的所有命令。

花括號中的第一個命令將把如下行:

D08/28/2000

變換成:

08/28/2000 OUTY INNY

當然,現在的格式還不完美,但沒關系。我們將在進行過程中逐漸細化模式空間的內容。后面 12 行的最后效果是將數據變換成三個字母的格式,最后一行從數據中除去三個斜杠。最后得到這一行:

Aug 28 2000 OUTY INNY

OUTY 和 INNY 字段是占位符,以后將被替換。現在還不能確定它們,因為如果美元金額為負,將把 OUTY 和 INNY 設置成 “misc” 和 “-”,但是,如果美元金額為正,將分別把它們更改成 “-” 和 “inco”。既然還沒有讀入美元金額,所以,需要暫時使用占位符。

細化
現在進一步細化:

1d /^^/d s/[[:cntrl:]]//g /^D/ {
s/^D/(.*/)//1/tOUTY/tINNY/t/
s/^01/Jan/ s/^02/Feb/
s/^03/Mar/ s/^04/Apr/
s/^05/May/ s/^06/Jun/
s/^07/Jul/ s/^08/Aug/
s/^09/Sep/ s/^10/Oct/
s/^11/Nov/ s/^12/Dec/
s:^/(.*/)//(.*/)//(.*/):/2 /1 /3:
N N N
s//nT/(.*/)/nN/(.*/)/nP/(.*/)/NUM/2NUM/t/tY/t/t/3/tAMT/1AMT/
s/NUMNUM/-/ s/NUM/([0-9]*/)NUM//1/
s//([0-9]/),//1/ }

后七行有些復雜,所以將詳細討論它們。首先,連續使用三個 ‘N’ 命令。’N’ 命令告訴 sed 將下一行讀入輸入中,然后將其附加到當前模式空間。這三個 ‘N’ 命令導致將下三行附加到當前模式空間緩沖區,現在這一行看起來如下:

28 Aug 2000 OUTY INNY /nT-8.15/nN/nPCHECKCARD SUPERMARKET

sed 的模式空間變得很難看 — 需要除去額外的新行,并執行某些附加的格式化。要這樣做,將使用替代命令。要匹配的模式為:

‘/nT.*/nN.*/nP.*’

這將與后面依次跟有 ‘T’、零或多個字符、新行、’N'、任何數量的字符、新行、’P'、以及任何數量字符的新行匹配。呀!這個規則表達式將與剛剛附加到模式空間的三行的全部內容匹配。但我們要重新格式化該區域,而不是整個替換它。美元金額、支票號(如果有的話)和描述需要出現在替換字符串中。要這樣做,我們用帶有反斜杠的圓括號括起那些“感興趣部分”,以便可以在替換字符串中引用它們(使用 ‘/1′、’/2/ 和 ‘/3′ 來告訴 sed 將它們插入到何處)。以下是最后的命令:

s//nT/(.*/)/nN/(.*/)/nP/(.*/)/NUM/2NUM/t/tY/t/t/3/tAMT/1AMT/

該命令將我們的行變換成:

28 Aug 2000 OUTY INNY NUMNUM Y CHECKCARD SUPERMARKET AMT-8.15AMT

雖然該行正變得好一些,但是,有幾件事一看就有點…啊…有趣。首先是那個愚蠢的 “NUMNUM” 字符串 — 其目的何在?如果查看 sed 腳本的后兩行,就會發現其目的,后兩行將把 “NUMNUM” 替換成 “-”,而把 “NUM”<number>”NUM” 替換成 <number>。如您所見,用愚蠢的標記括起支票號允許我們在該字段為空時方便地插入一個 “-”。

結束嘗試
最后一行除去數字后的逗號。它把如 “3,231.00″ 這樣的美元金額轉換成我使用的格式 “3231.00″。現在,讓我們看一下最終腳本:

最終的“QIF 到文本”腳本 1d /^^/d s/[[:cntrl:]]//g /^D/ { s/^D/(.*/)//1/tOUTY/tINNY/t/
s/^01/Jan/ s/^02/Feb/ s/^03/Mar/ s/^04/Apr/ s/^05/May/
s/^06/Jun/ s/^07/Jul/ s/^08/Aug/ s/^09/Sep/ s/^10/Oct/
s/^11/Nov/ s/^12/Dec/ s:^/(.*/)//(.*/)//(.*/):/2 /1 /3:
N N N s//nT/(.*/)/nN/(.*/)/nP/(.*/)/NUM/2NUM/t/tY/t/t/3/tAMT/1AMT/
s/NUMNUM/-/ s/NUM/([0-9]*/)NUM//1/ s//([0-9]/),//1/
/AMT-[0-9]*.[0-9]*AMT/b fixnegs
s/AMT/(.*/)AMT//1/ s/OUTY/-/ s/INNY/inco/
b done :fixnegs s/AMT-/(.*/)AMT//1/ s/OUTY/misc/
s/INNY/-/ :done }

附加的十一行使用替代和一些分支功能來美化輸出。首先看一下這行:

/AMT-[0-9]*.[0-9]*AMT/b fixnegs

該行包含一個格式為 “/regexp/b label” 的分支命令。如果模式空間與規則表達式匹配,sed 將分支到 fixnegs 標號。您應該可以輕易找到該標號,它在代碼中為 “:fixnegs”。如果規則表達式不匹配,則以常規方式繼續處理下一個命令。

既然您理解該命令本身的工作原理,讓我們看一下分支。如果看一下分支規則表達式,將看到它與后面依次跟有 ‘-’、任意數量的數字、一個 ‘.’、任意數量的數字和 ‘AMT’ 的字符串 ‘AMT’ 匹配。就象我確信您已猜到一樣,該規則表達式專門處理負的美元金額。在這之前,用 ‘ATM’ 括起美元金額,以便以后可以輕易找到它。因為規則表達式只與以 ‘-’ 開始的美元金額匹配,所以,該分支只在恰巧處理借款時才發生。如果正處理貸款,應該將 OUTY 設置成 ‘misc’,將 INNY 設置成 ‘-’,并且應該除去貸款數量前面的負號。如果跟蹤代碼的流程,將看到實際情況正是這樣。如果不執行分支,則用 ‘-’ 替換 OUTY,用 ‘inco’ 替換 INNY。完成了!現在輸出行是完美的:

28 Aug 2000 misc - - Y CHECKCARD SUPERMARKET -8.15

別犯糊涂
如您所見,只要循序漸進地解決問題,使用 sed 轉換數據就沒有那么難。不要試圖使用一個 sed 命令或一下子解決所有問題。相反,要朝著目標逐步進行,并不斷改進 sed 腳本,直到其輸出正如您希望那樣為止。sed 有許多功能,希望您已非常熟悉其內部工作原理并繼續努力以進一步掌握它!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/535769.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/535769.shtml
英文地址,請注明出處:http://en.pswp.cn/news/535769.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Oracle GoldenGate微服務架構

Oracle GoldenGate支持兩種架構&#xff0c;經典架構和微服務架構&#xff08;MA&#xff09;。 可以出于以下目的配置Oracle GoldenGate&#xff1a; 從一個數據庫中靜態提取數據記錄&#xff0c;并將這些記錄加載到另一個數據庫中。連續提取和復制事務性數據處理語言&#…

Oracle GoldenGate經典架構

可以使用Oracle GoldenGate Classic Architecture從命令行配置和管理數據復制。 圖示的說明logicalarch2.png 注意&#xff1a; 這是基本配置。根據業務需求和用例&#xff0c;可以配置此模型的不同變體。 1、Manager Manager是Oracle GoldenGate的控制過程。必須先在Oracl…

WordPress 首頁顯示摘要

這里的方法不需要你另外裝插件。 1、使用more標簽 (缺點&#xff1a;每次都要加一下這個東西&#xff0c;不靈活只能一刀切。優點&#xff1a;方法比較正規不需要改動模版) 在你需要截斷的地方(就是你的編輯框)加 <!–more–> 代碼. 2、使用the_excerpt標簽 (缺點&#x…

Oracle GoldenGate復制過程

這兩種Oracle GoldenGate體系結構共有許多數據復制過程。 1、什么是Extract&#xff1f; Extract是一個過程&#xff0c;該過程被配置為針對源數據庫運行或被配置為在下游挖掘數據庫&#xff08;僅Oracle&#xff09;上運行&#xff0c;以捕獲在其他位置的真實源數據庫中生成…

awk教程入門與實例練習(一)

Awk 是一種非常好的語言&#xff0c;同時有一個非常奇怪的名稱。在本系列&#xff08;共三篇文章&#xff09;的第一篇文章中&#xff0c;Daniel Robbins 將使您迅速掌握 awk 編程技巧。隨著本系列的進展&#xff0c;將討論更高級的主題&#xff0c;最后將演示一個真正的高級 a…

HDFS-簡介

HDFS 是 Hadoop Distribute File System 的簡稱&#xff0c;意為&#xff1a;Hadoop 分布式文件系統&#xff0c;是一種旨在在商品硬件上運行的分布式文件系統。它與現有的分布式文件系統有許多相似之處。但是&#xff0c;與其他分布式文件系統的區別很明顯。HDFS具有高度的容錯…

awk教程入門與實例練習(二)

在這篇 awk 簡介的續集中&#xff0c;Daniel Robbins 繼續探索 awk&#xff08;一種很棒但有怪異名稱的語言&#xff09;。Daniel 將演示如何處理多行記錄、使用循環結構&#xff0c;以及創建并使用 awk 數組。閱讀完本文后&#xff0c;您將精通許多 awk 的功能&#xff0c;而且…

HDFS-配置項

一、core-site.xml與core-default.xml core-default.xml與core-site.xml的功能是一樣的&#xff0c;如果在core-site.xml里沒有配置的屬性&#xff0c;則會自動會獲取core-default.xml里的相同屬性的值 <configuration><property><!-- 這個屬性用來指定namenod…

awk教程入門與實例練習(三)

在 awk 系列的這篇總結中&#xff0c;Daniel 向您介紹 awk 重要的字符串函數&#xff0c;以及演示了如何從頭開始編寫完整的支票簿結算程序。在這個過程中&#xff0c;您將學習如何編寫自己的函數&#xff0c;并使用 awk 的多維數組。學完本文之后&#xff0c;您將掌握更多 awk…

HDFS-常用命令

1. -help&#xff1a;顯示幫助信息 hadoop fs -help rmshel2. -ls&#xff1a;顯示目錄信息 hadoop fs -ls /3. -mkdir&#xff1a;在HDFS上創建目錄 hadoop fs -mkdir -p /user/ha4. -moveFromLocal&#xff1a;從本地剪切粘貼到HDFS hadoop fs -moveFromLocal ~/test.txt…

如何關閉WINDOWS2003 DEP數據保護功能

近來很多朋友和客戶都使用了WINDOWS2003來架設自己的GAME SERVER,但有很多朋友反映說,不如WINDOWS2000好,原因不是穩定,而是成功率高,和簡單.但我個人覺得WINDOWS2003還是不錯的系統,如果朋友們都不用這個系統,而用WINDOWS2000 有點不值得了.我就開始找尋這樣的問題.我對GAME 不…

JDK源碼解析之 java.lang.Thread

位于java.lang包下的Thread類是非常重要的線程類&#xff0c;它實現了Runnable接口&#xff0c;今天我們來學習一下Thread類&#xff0c;在學習Thread類之前&#xff0c;先介紹與線程相關知識&#xff1a;線程的幾種狀態、上下文切換&#xff0c;然后接著介紹Thread類中的方法的…

TASKLIST

TASKLIST [/S system [/U username [/P [password]]]] [/M [module] | /SVC | /V] [/FI filter] [/FO format] [/NH]參數列表:/S system 指定連接到的遠程系統。/U [domain/]user 指定使用哪個用戶執行這個命令。/P [password] 為指定的用戶指定密碼。/SVC 顯示每個進程中的服務…

JDK源碼解析之 java.lang.ThreadLocal

此類提供線程局部變量。這些變量與普通變量不同&#xff0c;每個訪問一個線程&#xff08;通過其get或set方法&#xff09;的線程 都有其自己的&#xff0c;獨立初始化的變量副本。 ThreadLocal實例通常是希望將狀態與線程關聯的類中的私有靜態字段&#xff08;例如&#xff0c…

華爾街頂級大師胡立陽名言

1.不要聽“親朋好友”的話&#xff0c;他們只會讓你成為“平凡人”。 2.不要只會“用功讀書”&#xff0c;重要的是“要讀對書”。  3&#xff0e;不要只是“努力工作”&#xff0c;重要的是“做對工作”。   4.不要指示結交“志趣相投”的朋友&#xff0c;否則你永遠只看到…

JDK源碼解析之 Java.lang.Enum

Enum是一個特殊的類. 我們不能以class Xxx extends Enum的方式手動繼承, 必須寫成enum Xxx的形式; 然而這段枚舉類的定義在編譯之后又變回了class Xxx extends Enum. 一、類定義 public abstract class Enum<E extends Enum<E>>implements Comparable<E>, …

Linux下的一些簡單網絡配置命令介紹

1、 ifconfig可以使用ifconfig命令來配置并查看網絡接口的配置情況。例如&#xff1a;&#xff08;1&#xff09; 配置eth0的IP地址&#xff0c; 同時激活該設備。#ifconfig eth0 192.168.1.10 netmask 255.255.255.0 up&#xff08;2&#xff09; 配置eth0別名設備eth0:1的IP地…

JDK源碼解析之 java.lang.Throwable

在 Java 中&#xff0c;所有的異常都有一個共同的祖先 Throwable&#xff08;可拋出&#xff09;。Throwable 指定代碼中可用異常傳播機制通過 Java 應用程序傳輸的任何問題的共性。 一、類定義 public class Throwable implements Serializable {}Serializable&#xff1a;可…

JDK源碼解析之 java.lang.Error

java.lang.Error 錯誤。是所有錯誤的基類&#xff0c;用于標識嚴重的程序運行問題。這些問題通常描述一些不應被應用程序捕獲的反常情況。 一、源碼部分 //繼承了java.lang.Throwable public class Error extends Throwable {//適用于java序列化機制,過判斷類的serialVersionU…

linux命令之有關網絡的操作命令

1&#xff0e;hostname 命令&#xff08;1&#xff09;一般格式&#xff1a;hostname [選項] [主機名]&#xff08;2&#xff09;說明&#xff1a;顯示或設置系統的主機名&#xff1b;如果無任何選項和主機名&#xff0c;則用于顯示系統的主機名。&#xff08;3&#xff09…