¿Cómo omitir el reemplazo de la primera aparición de un carácter en cada línea?

¿Cómo omitir el reemplazo de la primera aparición de un carácter en cada línea?

Tengo algunos archivos en el formato

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;

Deseo reemplazar cada aparición del guión bajo (_) con dos puntos (:) EXCEPTO el primero. Quiero una salida como esta:

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;

Sé que puedo usar sed -i '' 's/_/:/g' old_filepara reemplazar TODOS (o sed 's/_/:/g' old_file > new_file) y que podría agregar números para reemplazar solo la segunda, cuarta aparición:

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

Pero, ¿cómo reemplazar cada aparición en cada línea PERO la primera?

Respuesta1

Usando GNU sed(otras versiones pueden comportarse de manera diferente, graciasjackman):

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

Esto cambiará todo _para :omitir la primera aparición en cada línea.

Respuesta2

Usando Posix-sedconstrucciones solo nos gusta como:

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

Según las sugerencias de Stéphane, a continuación se muestran algunos métodos más:

$ 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 

Respuesta3

¿Está bien? Puede utilizar _como separador de campos e imprimir:

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

Como esto:

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

Si la estructura es la misma para cada línea, puede codificar el número de campos para evitar el bucle (se ejecuta en aproximadamente 2/3 del tiempo según una prueba preliminar muy aproximada):

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

Respuesta4

Aquí hay otro awkscript simple (Linux estándar gawk), sin bucles:

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
}

correr:

awk -f script.awk input.txt

o:

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

información relacionada