各行で最初に出現する文字の置き換えをスキップするにはどうすればよいですか?

各行で最初に出現する文字の置き換えをスキップするにはどうすればよいですか?

形式のファイルがいくつかあります

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_fileALL (または ) を置き換えるために を使用できることsed 's/_/:/g' old_file > new_file、また 2 番目、4 番目などの出現部分のみを置き換えるために数字を追加できることはわかっています。

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

しかし、最初の行を除く各行のすべての出現箇所を置き換えるにはどうすればよいでしょうか?

答え1

GNUを使用sed(他のバージョンでは動作が異なる可能性があります。グレン・ジャックマン):

 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

関連情報