我想使用 sed 在最後一行插入一些文字的新字串,

我想使用 sed 在最後一行插入一些文字的新字串,

在文件中搜尋具有給定字串的最後一行,以在該匹配項後面添加一行。例子:

輸入:

Apple
Banana
Apple
Orange
Apple
Grapefruit

輸出:

Apple
Banana
Apple
Orange
Apple
I am new string replaced at last apple
Grapefruit

答案1

使用 GNUsed你可以這樣做:

sed ':a;N;$! ba;s/.*\nApple/&\nYour appended line/'

此模式:a;N;$! ba將檔案中的行追加到緩衝區,N而未 ( ) 到達檔案末端($位址)!(跳到:awith ba)。因此,如果退出循環,所有行都在緩衝區中,並且搜尋模式.*\nApple會匹配整個文件,直到以 . 開頭的最後一行Apple。在&替換字串中插入整個匹配項並附加您的文字。

sed也適用於其他版本的便攜式解決方案是

sed -e ':a' -e 'N;$! ba' -e 's/.*\(\n\)Apple/&\1Your appended line/'

這裡,腳本在標籤處被分割,而不是\n在替換字串中使用(不保證與非 GNU 一起工作sed),我們引用引用包圍的模式中的\(\)字串\1

答案2

我看到了這個例子這裡

sed -i -e "\$aTEXTTOEND" <filename>

資訊:

i: edit files in place    
e: add the script to the commands to be executed    
$: sed address location
a: append command
TEXTTOEND: text to append to end of file

答案3

我假設您的範例輸入是一個名為fruits.txt.


如果你想在最後一次出現「Apple」之後插入一行,可以sed這樣做:

sed -rz 's/(^(.*\n)?Apple)(\n|$)/\1\ninserted line\n/'

-r選項啟用擴充正規表示式。
-z選項指示sed採用 NUL 字元(ASCII 代碼 0)作為行分隔符號而非普通的換行符。這樣,整個文本文件將立即處理,而不是逐行處理。

sed命令在s/PATTERN/REPLACEMENT/中搜尋(擴展的,因為-r)正規表示式,PATTERN並將其替換為計算的REPLACEMENT字串。

正規表示式(^(.*\n)?Apple)(\n|$)符合從開頭 ( ^) 到最後出現的任意行數,Apple後面跟著換行符號 ( \n) 或檔案結尾 ( $)。

現在整場比賽被替換為\1\ninserted line\n,其中\1代表第一個比賽組的原始內容,即直到 的所有內容Apple。因此,實際上它在最後一次出現“Apple”之後插入了inserted line前後的換行符 ( )。\n

如果「Apple」行是檔案中的第一行、最後一行或唯一一行,這也適用。

範例輸入檔(在範例中新增一行,以使行為清晰):

Apple
Banana
Apple
Orange
Apple
Cherry

輸出範例:

Apple
Banana
Apple
Orange
Apple
inserted line
Cherry

如果您對結果感到滿意並希望fruits.txt就地編輯,而不是僅僅輸出修改,您可以添加選項-i

sed -irz 's/(^(.*\n)?Apple)(\n|$)/\1\ninserted line\n/'

如果您只想將一行文字附加到該文件的末尾,那麼sed這不是最佳工具。

您可以簡單地使用 Bash 的>>附加輸出重定向,然後:

echo "I am new string replaced at last apple" >> fruits.txt

>>獲取其左側命令的標準輸出(echo此處的命令只是將其參數列印到標準輸出)並將其附加到右側指定的檔案中。如果該文件尚不存在,則會建立該文件。

答案4

在這個答案中:

  1. sed+tac(雙輸入反轉)
  2. 雙輸入 AWK
  3. Perl 雙輸入
  4. 具有雙輸入反轉的替代 Perl

sed + tac

此方法使用 3 個過程,首先反轉文件,使用 sed 查找第一個匹配項並在第一個匹配後插入所需的文本,然後再次反轉文本。

$ tac input.txt | sed '0,/Apple/{s/Apple/NEW THING\n&/}' | tac 
Apple
Banana
Apple
Orange
Apple
NEW THING
something else
something other entirely
blah

基本概念與下面編寫的替代 perl 版本相同:反向行列表中的第一個匹配項是原始列表中的最後一個匹配項。就使用者而言,這種方法的優點是簡單性和可讀性。

這種方法對於小檔案來說效果很好,但對於大檔案來說很麻煩,並且可能需要相當長的時間來處理大量的行。

AWK

awk 可以為您想要做的事情提供一點友誼:

$ awk -v n="AFTER LAST APPLE" 'NR==FNR&&/Apple/{l=NR};NR!=FNR{if(FNR==l){print $0;print n}else print}' input.txt input.t>
Apple
Banana
Apple
Orange
Apple
AFTER LAST APPLE
something else
something other entirely
blah

這裡的基本思想是將輸入文件提供給 awk 兩次 - 首先查找最後一個蘋果的位置,第二次在我們傳遞從第一次迭代中找到的最後一個“蘋果”的位置時插入文本。

完成這項工作的關鍵是評估NR(不斷計算所有已處理的行、總數)和FNR(目前文件中的行號)變數。當這兩個文件不相等時,我們知道我們正在處理第二個文件,因此我們知道我們已經完成了第一次查找 Apple 最後出現的位置。

由於我們讀取檔案兩次,因此效能將取決於檔案的大小,但它比 sed + tac 組合更好,因為我們不需要反轉檔案兩次。

珀爾

perl -sne '$t+=1;$l=$. if /Apple/ and $.==$t;
          if($t!=$.){if($.==$l){print $_ . $n . "\n";}else{print $_}};
          close ARGV if eof;' -- -n="AFTER LAST APPLE" input.txt input.txt

Perl 解決方案遵循與 AWK 解決方案相同的想法。我們傳遞輸入兩次,並使用第一次傳遞的檔案來尋找 Apple 最後一次出現的位置,並將其行號儲存到$l變數中。這裡與 awk 的不同之處在於,perl 中沒有FNR變量,因此我們必須使用$t+=1andclose ARGV if eof來達到此目的。

這裡的另一個不同之處是-sperl 允許使用 switch 來傳遞參數。在這種情況下,我們要插入的字串是透過-nswitch 傳遞的。

替代 Perl

這是在 Perl 中執行此操作的另一種方法。這個想法是簡單地將檔案讀入行數組,然後反轉該數組。反轉數組中的第一個符合項目是原始行列表中的最後一個匹配項。因此,我們可以在該行之前插入所需的文本,並再次反轉列表:

$ perl -le '@a1=<>;END{do{push @a2,"NEW LINE\n" and $f=1 if $_ =~ /Apple/ and !$f; push @a2,$_} for reverse(@a1); print reverse(@a2)}' input.txt      
Apple
Banana
Apple
Orange
Apple
NEW LINE
something else
something other entirely
blah

相關內容