Wie überspringe ich das Ersetzen des ersten Vorkommens eines Zeichens in jeder Zeile?

Wie überspringe ich das Ersetzen des ersten Vorkommens eines Zeichens in jeder Zeile?

Ich habe einige Dateien im Format

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;

Ich möchte jedes Vorkommen des Unterstrichs (_) durch einen Doppelpunkt (:) ersetzen, AUSSER dem ersten. Ich möchte eine Ausgabe wie diese:

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_fileIch weiß, dass ich ALLE (oder ) ersetzen kann sed 's/_/:/g' old_file > new_fileund dass ich Zahlen hinzufügen kann, um nur das 2., 4. oder so Vorkommen zu ersetzen:

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

Aber wie ersetzt man jedes Vorkommen in jeder Zeile AUSSER dem ersten?

Antwort1

Verwendung von GNU sed(andere Versionen verhalten sich möglicherweise anders, dankeGlenn Jackman):

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

Dadurch wird alles so geändert, _dass :das erste Vorkommen in jeder Zeile übersprungen wird.

Antwort2

Wir verwenden Posix-sedausschließlich Konstrukte wie:

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

Basierend auf den Vorschlägen von Stephane folgen hier noch einige weitere Methoden:

$ 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 

Antwort3

Ist awk okay? Sie könnten es _als Feldtrennzeichen verwenden und ausdrucken:

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

So was:

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

Wenn der Aufbau in allen Zeilen gleich ist, könnte man zur Vermeidung der Schleife die Anzahl der Felder fest codieren (läuft laut einem sehr groben Vorversuch in ca. 2/3 der Zeit):

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

Antwort4

Hier ist ein weiteres einfaches awkSkript (Standard-Linux gawk), ohne Schleifen:

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
}

laufen:

awk -f script.awk input.txt

oder:

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

verwandte Informationen