替换文件的倒数第二行的“模式”

时间:2016-07-29 01:14:25

标签: sed

我必须在文件的倒数第二行 - file.txt上用“string”替换“pattern”。 以下三个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”替换为“green” 湾用“胡萝卜”替换整条线,无论它包含什么

3 个答案:

答案 0 :(得分:8)

要在第二行到最后一行将Sweet更改为绿色,但前提是该行包含Sweet pepper

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

要将整个倒数第二行替换为胡萝卜,无论它包含什么,

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

如何运作

让我们一步一步地检查这个命令:

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

    这将交换模式空间(保存最近读取的行)和保留空间。

    完成此操作后,保留空间将包含最近读取的行,模式空间将包含前一行。 (例外情况是我们刚读完第一行。在这种情况下,保留空间将有第一行,模式空间将为空。)

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

    当我们在$指示的最后一行时,模式空间保持倒数第二行,我们可以执行我们喜欢的任何替换或其他命令。完成后,我们使用p打印倒数第二行。最后,我们用x交换模式并再次保留空间,以便模式空间将再次包含最后一行。 sed将打印此内容,因为默认情况下,在命令的末尾,sed会打印模式空间中的任何内容。

  • 1d

    当我们在1指示的第一行时,patten空格为空(因为没有前一行)并且我们将其删除(d)。

    < / LI>

一种更简单的方法

这种方法易于理解,代价是执行速度较慢:

$ 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来反转行的顺序。观察:

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

通过这种方式,倒数第二行成为第2行。因此,我们只是告诉sed在第2行操作。之后,我们再次使用tac来放置行但是正确顺序。

答案 1 :(得分:2)

您可能会发现awk脚本更易于理解,维护,移植等等:

string

想要在结束前更改第3行而不是在结束前更改第1行?这只是将public class RootObject { ... public override string ToString() { return Name; } } 更改为$ 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

答案 2 :(得分: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

Sed解决方案

$ 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