如何跳過替換每行中第一次出現的字元?

如何跳過替換每行中第一次出現的字元?

我有一些格式的文件

Y15-SUB-B04-P17-BK_M02734_4_000000000-ANNUF_1_1111_24724_4878;size=1;
Y15-SUB-B05-P22-LM_M02734_4_000000000-ANNUF_1_1111_20624_14973;size=1;
Y15-SUB-B05-P22-LM_M02734_4_000000000-ANNUF_1_1103_11326_10379;size=1;

我希望將每次出現的底線 (_) 替換為冒號 (:),除了第一個。我想要這樣的輸出:

Y15-SUB-B04-P17-BK_M02734:4:000000000-ANNUF:1:1111:24724:4878;size=1;
Y15-SUB-B05-P22-LM_M02734:4:000000000-ANNUF:1:1111:20624:14973;size=1;
Y15-SUB-B05-P22-LM_M02734:4:000000000-ANNUF:1:1103:11326:10379;size=1;

我知道我可以用它sed -i '' 's/_/:/g' old_file來替換 ALL (或sed 's/_/:/g' old_file > new_file),並且我可以添加數字來僅替換第二次、第四次左右的出現:

sed 's/_/:/2' old_file > new_file

但是如何替換每一行中除第一行之外的所有出現的情況呢?

答案1

使用GNUsed(其他版本可能表現不同,謝謝格倫傑克曼):

 sed -i'' 's/_/:/2g' file

這會將所有內容變更_:跳過每行的第一次出現。

答案2

僅使用Posix-sed我們喜歡的結構:

$ sed -e '
     y/_/\n/
     s/\n/_/
     y/\n/:/
' inp.file

根據 Stephane 的建議,還有一些方法如下:

$ perl -pe 's/(^\G.*?_)?.*?\K_/:/g' inp.file 

$ perl -pe 'my $n; s/_/$n++?":":$&/ge' inp.file 

$ perl -pe 's/_\K(.*)/$1 =~ y|_|:|r/e' inp.file 

答案3

awk還好嗎?您可以用作_字段分隔符,並列印出來:

<field 1>_<field 2>:<field n>:<field n+1>:...

像這樣:

awk -F_ '{ printf("%s_%s", $1, $2); for (x = 3; x <=NF; x++) { printf(":%s", $x); }; printf("\n"); }'

如果每行的結構相同,您可以對欄位數量進行硬編碼以避免循環(根據非常粗略的初步試驗,運行時間約為 2/3):

awk -F_ '{printf("%s_%s:%s:%s:%s:%s:%s:%s\n", $1, $2, $3, $4, $5, $6, $7, $8);}'

答案4

這是另一個簡單的awk腳本(標準 Linux gawk),沒有循環:

cat script.awk
match($0,/^[^_]*_/,a){ # match current line to first _ (including) into a[0] variable
   sub(a[0],"");       # remove a[0] from current line
   gsub("_",":");      # replace all _ to : in current line
   print a[0]""$0;     # output a[0] and current line
}

跑步:

awk -f script.awk input.txt

或者:

awk 'match($0,/^[^_]*_/,a){sub(a[0],"");gsub("_",":");print a[0]""$0;}' input.txt

相關內容