2016-07-29 41 views
3

我必須用文件倒數第二行上的「字符串」替換「模式」 - file.txt。 以下三個sed命令能夠打印倒數第二行。但我需要用「字符串」替換「模式」。任何幫助?替換文件的倒數第二行上的「模式」

sed -e '$!{h;d;}' -e x file.txt 

sed -n 'x;$p' file.txt 

sed 'x;$!d' file.txt 

$ cat file.txt 
cabbage 
spinach 
collard greens 
corn salad 
Sweet pepper 
kale 

如何替換文件(甜椒)的第二到最後一行:
一個。如果倒數第二行包含「甜椒」,則將「Sweet」替換爲「綠色」
b。

$ sed 'x; ${/Sweet pepper/s/Sweet/Green/;p;x}; 1d' file.txt 
cabbage 
spinach 
collard greens 
corn salad 
Green pepper 
kale 

更換整的:用「胡蘿蔔」,不管它包含

+1

sed的是區分大小寫的,我已經改變了'甜「到」甜「# – sjsam

回答

5

要在第二個變化甜到綠色,再到最後一行,但只有在該行包含Sweet pepper更換整條生產線倒數第二行,不管它包含什麼,胡蘿蔔:

$ sed 'x; ${s/.*/carrots/;p;x}; 1d' file.txt 
cabbage 
spinach 
collard greens 
corn salad 
carrots 
kale 

它是如何工作

讓我們充分利用這個命令並檢查它的一個步驟的T A時間:

sed 'x; ${s/.*/carrots/;p;x}; 1d' 
  • x

    這種交換模式空間(持有最近讀線)和保持空間。

    完成後,保持空間將包含最近讀取的行,並且模式空間將包含上一行。 (唯一的例外是,當我們剛纔所讀的第一行。在這種情況下,保持空間將有第一行和模式空間將是空的。)

  • ${s/.*/carrots/;p;x}

    當我們都在最後一行,由$表示,模式空間保存着倒數第二行,我們可以執行任何我們喜歡的替換或其他命令。當我們完成後,我們打印倒數第二行p。最後,我們交換模式,並再次使用x保留空間,以便模式空間再次包含最後一行。 sed將打印此項,因爲默認情況下,在命令的末尾,sed將打印模式空間中的任何內容。

  • 1d

    當我們都在第一線,由1指出,彭定康的空間是空的(因爲沒有前行),我們將其刪除(d)。

一個更加簡單的方法

這種方法很容易以較低的執行速度爲代價來理解:

$ tac file.txt | sed '2 {/Sweet pepper/s/Sweet/Green/}' | tac 
cabbage 
spinach 
collard greens 
corn salad 
Green pepper 
kale 

而且,胡蘿蔔:

$ tac file.txt | sed '2 s/.*/carrots/' | tac 
cabbage 
spinach 
collard greens 
corn salad 
carrots 
kale 

如何它的工作原理:在這裏,我們使用tac轉erse線的順序。注意:

$ tac file.txt 
kale 
Sweet pepper 
corn salad 
collard greens 
spinach 
cabbage 

這樣,第二個到最後行成爲2號線。因此,我們只是簡單地告訴sed來對2號線運營之後,我們使用tac再次把線,但按正確的順序。

+1

我以爲'tac',但你已經把它。 :)這就是說,我也喜歡第一個解決方案:)所以這個++的東西。 – sjsam

+0

它的工作原理。你簡直太棒了,能夠非常清楚準確地解釋。保持。 – Arun

2

您可能會發現一個awk腳本更容易理解,維護,端口等:

$ awk 'NR==FNR{tgt=NR-1;next} (FNR==tgt) && /Sweet pepper/ { $1="green" } 1' file file 
cabbage 
spinach 
collard greens 
corn salad 
green pepper 
kale 

$ awk 'NR==FNR{tgt=NR-1;next} (FNR==tgt) { $0="carrots" } 1' file file 
cabbage 
spinach 
collard greens 
corn salad 
carrots 
kale 

到底想要的,而不是結束前1號線前更改3號線?這僅僅是簡單的,明顯的調整來改變-1-3

$ awk 'NR==FNR{tgt=NR-3;next} (FNR==tgt) { $0="carrots" } 1' file file 
cabbage 
spinach 
carrots 
corn salad 
Sweet pepper 
kale 
+0

既然'file'傳遞了兩次,awk是否足夠聰明以存儲單個副本? – sjsam

+0

@sjsam操作系統可能足夠聰明,足以緩存它,如果它足夠小。鑑於此,優化Awk來做到這一點可能是不明智的。 – tripleee

+0

@sjsam idk,但無論如何,它都會在眨眼之間發生,除非文件是絕對巨大的。 –

1

awk的解決方案

$ cat 38649053 
cabbage 
spinach 
collard greens 
corn salad 
Sweet pepper 
kale 
$tac 38649053 | awk 'NR==2{if($0=="Sweet pepper")#is record sweet pepper? 
{ 
$1="green"} #changing sweet to green , note $1 is the first field 
else{ 
$0="carrot" # $0 is the whole record which replaced by carrot 
}} 
{record[NR]=$0} #adding each record to an record number-indexed array 
END{ #printing the records in reverse at the end 
i=NR;for(;i>=1;i--)print record[i]} 
' 
cabbage 
spinach 
collard greens 
corn salad 
green pepper 
kale 

桑達解決方案

$ cat 38649053 
cabbage 
spinach 
collard greens 
corn salad 
Sweet pepper 
kale 
$ lines=$(wc -l <38649053) # lines contains the total # of lines 
$ ((s2l=--lines)) # storing the second to last line number to s2l 
$ sed -E "${s2l}"'{/^Sweet pepper$/!s/.*/carrot/;/^Sweet pepper$/s/Sweet/green/}' 38649053 
# applying the sed to the required line 
cabbage 
spinach 
collard greens 
corn salad 
green pepper 
kale 
+0

只要程序員的時間比計算機時間更昂貴,因爲它幾乎總是這樣,然後'tac'大大簡化了這個問題。 +1。 – John1024

+0

當然,你也可以很容易地在'sed'中使用'tac'。 'tac文件| sed'2s /甜椒/青椒/'| tac' – tripleee