2017-07-17 61 views
2

我有一個用例,我需要搜索並替換文件中最後一次出現的字符串,並將更改寫回文件。下面的情況是該用例的簡化版本:反向文件使用tac和sed

我正在嘗試將文件反轉,使一些更改將其反轉回來並寫入文件。我嘗試了下面的代碼片段此:

tac test | sed s/a/b/ | sed -i '1!G;h;$!d' test 

測試與內容的文本文件:

a 
1 
2 
3 
4 
5 

我期待這個命令不會更改文件的順序,但它實際上已經扭轉了內容:

5 
4 
3 
2 
1 
b 

我怎樣才能使替代以及保留文件的順序?

+0

請參閱:[Bash:如何使用sed替換文件中最後一次出現的內容?](https://stackoverflow.com/q/10106292/3776858)或https://www.google.com/# q = bash + replace + last + occurrence + in +文件 – Cyrus

+0

這裏的區別是我需要寫回文件。 – seriousgeek

回答

2

另一種方式是用戶grep得到包含要更改文本的最後一行的數字,然後用sed改變該行:

$ linno=$(grep -n 'abc' <file> | tail -1 | cut -d: -f1) 

$ sed -i "${linno}s/abc/def/" <file> 
+1

你也可以使用sed的'='命令..只得到匹配的行號...例如:'seq 20 | sed -n'/ 4/='|尾巴-1' – Sundeep

+1

我喜歡它!每天學些新東西! – Jack

2

嘗試cat test | rev | sed -i '1!G;h;$!d' | rev

或者你也可以只使用sed coomand: 例如要替換ABCDEF

你需要 'G' 添加到您的sed結束:

sed -e 's/\(.*\)ABC/\1DEF/g' 

這告訴sed將替換您的正則表達式(「全局」)的每一次出現,而不是僅第一次出現。

您還應該添加一個$,如果你想確保它更換就行了ABC的最後出現:

sed -e 's/\(.*\)ABC$/\1DEF/g' 

編輯

或者乾脆添加其他| tac到您的命令: tac test | sed s/a/b/ | sed -i '1!G;h;$!d' | tac

2

您可以tac文件,對德第一次出現替代應用首創模式,tac一次tee結果你用原來的名字重新命名它之前的臨時文件:

tac file | sed '0,/a/{s//b/}' | tac > tmp && mv tmp file 
1

這是一種方式,使用awk一個命令來做到這一點。

第一個輸入文件:

cat file 
a 
1 
2 
3 
4 
a 
5 

現在這個awk命令:

awk '{a[i++]=$0} END{p=i; while(i--) if (sub(/a/, "b", a[i])) break; 
     for(i=0; i<p; i++) print a[i]}' file 
a 
1 
2 
3 
4 
b 
5 

要節省輸出回原來的文件使用:

awk '{a[i++]=$0} END{p=i; while(i--) if (sub(/a/, "b", a[i])) break; 
for(i=0; i<p; i++) print a[i]}' file >> $$.tmp && mv $$.tmp f 
1

另在AWK。首先測試文件:

$ cat file 
a 
1 
a 
2 
a 

和解決方案:

$ awk ' 
$0=="a" && NR>1 {    # when we meet "a" 
    print b; b=""    # output and clear buffer b 
} 
{ 
    b=b (b==""?"":ORS) $0  # gether the buffer 
} 
END {       # in the end 
    sub(/^a/,"b",b)   # replace the leading "a" in buffer b with "b" 
    print b     # output buffer 
}' file 
a 
1 
a 
2 
b 

寫回將其輸出重定向到一個臨時文件,它取代了原來的文件(awk ... file > tmp && mv tmp file)的情況,或者如果您正在使用GNU AWK v 4.1.0+你可以使用就地編輯(awk -i inplace ...)。